小さな管理機能を作ってみよう 第26話
初心者向け、PHPプログラム構築講座です。
初心者といっても、PHPの勉強を少し行い、LAMP環境が自分で構築でき、少しアプリケーションを作成しているレベルを対象とします。
まったくの初心者の場合は、わからない部分が出てくると思います。
できるだけ細かく説明は入れていきますが、説明がわからない場合は、PHPやMySQLの初心者講座をご覧ください。
対象のスキルレベル
- LAMP環境の構築
- PHP言語が読める
- HTML, CSS, Javascriptが少しわかる
- Bootstrapのドキュメントをみて、HTMLが書ける
- Ajax(非同期通信)を利用したことがある
- SESSIONを利用したことがある
構築環境
- Windows10
- XAMPP(PHP7.3.2, MariaDB 10.1.38)
Dashboardの実装
前回に引き続き、Dashboardのグラフ描画を実装していきます。③データ取得(非同期)と④数字描画、グラフ描画部分を行っていきます。
処理の概要は以下の通りです。
部署登録数推移グラフ
部署登録数推移グラフを実装していきます。Dashboard.php#getDeptsTransitionの呼び出しを行い、月別に集計したレコード件数を取得します。(年に関しては考慮していない実装になっています)
index.html(抜粋)
/* methodはDashboard.php#getUsersTransitionなので、getUsersTransitionを設定 */ $method('getUsersTransition'); /* 非同期通信を実行 */ $xhrNoValidate([], function(data, status, xhr){ /* データの配列はlist.rsに格納されている */ var rs = data.list.rs; /* updateSeriesを実行すると、そのままデータが反映され描画されます */ uchart.updateSeries([{ name: "ユーザ登録数", data: rs }]) }); /* グラフの描画設定 */ var options = { series: [], noData: { text: 'Loading...' }, chart: { height: 450, type: 'line', zoom: { enabled: false } }, dataLabels: { enabled: false }, stroke: { curve: 'straight' }, title: { text: '部署登録推移', align: 'left' }, grid: { row: { colors: ['#efefef', 'transparent'], // takes an array which will be repeated on columns opacity: 0.05 }, }, xaxis: { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], } }; /* グラフを描画する要素を取得し、グラフを描画 */ var dchart = new ApexCharts(document.querySelector('#depts'), options); dchart.render(); /* methodはDashboard.php#getDeptsTransitionなので、getDeptsTransitionを設定 */ $method('getDeptsTransition'); /* 非同期通信を実行 */ $xhrNoValidate([], function(data, status, xhr){ /* データの配列はlist.rsに格納されている */ var rs = data.list.rs; /* updateSeriesを実行すると、そのままデータが反映され描画されます */ dchart.updateSeries([{ name: "部署登録数", data: rs }]) });
画面に右下部署登録数推移のグラフが描画されれば成功です。
ここまでで、Dashboard(index.html)の実装は終了になります。お疲れ様です。
かなり進んできましたので、一度index.htmlの全ソースを公開していきたいと思います。うまくいかない場合は、こちらをコピーしてください。それでもうまくいかない場合は、/assets/js/script.jsがおかしい可能性がありますので、過去記事を見直してみて下さい。
Dashbaord(index.html)全ソース
index.html
<!doctype html> <html lang="ja" > <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="process"> <meta name="method"> <title>DASHBOARD | tech.pjin.jp</title> <!-- Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> <!-- Font Awesome CSS --> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous"> <!-- Animate.css CSS --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" /> <!-- Sawarabi Gothic --> <link href="https://fonts.googleapis.com/css?family=Sawarabi+Gothic" rel="stylesheet"> <link rel="stylesheet" href="assets/css/style.css" /> <style> .contents { overflow: hidden; } .scale-in .card { position:relative; } .scale-in .card::before { position:absolute; top:0; left:0; display:block; box-sizing:border-box; border:3px solid #ccc; border-radius: .25rem; width:100%; height:100%; content:""; opacity:0; transform:scale(1.2); transition:transform 0.3s, opacity 0.3s; } .scale-in .card:hover::before { opacity:1; transform:scale(1); } </style> </head> <body> <section class="loading d-flex justify-content-center align-items-center bg-light"> <div class="spinner shadow rounded d-flex justify-content-center align-items-center"> <p class="h4 text-secondary"><i class="fas fa-spinner fa-spin"></i> Loading...</p> </div> </section> <header> <nav class="navbar navbar-expand-lg navbar-light shadow bg-white fixed-top"> <div class="container-fluid"> <a class="navbar-brand" href="index.html"><i class="fas fa-paste"></i> BACK<span class="bland-red">OFFICE</span></a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNavDropdown"> <ul class="navbar-nav header-menu"> <li class="nav-item active"> <a class="nav-link active" href="index.html"><i class="fas fa-tachometer-alt"></i> DASHBOARD</a> </li> <li class="nav-item"> <a class="nav-link" href="users.html"><i class="fas fa-id-card-alt"></i> ユーザ管理</a> </li> <li class="nav-item"> <a class="nav-link" href="depts.html"><i class="far fa-building"></i> 部署管理</a> </li> </ul> <ul class="navbar-nav ms-auto me-3"> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle username" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false"> 管理者 </a> <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> <li><a class="dropdown-item" href="login.html"><i class="fas fa-sign-out-alt"></i> ログアウト</a></li> </ul> </li> </ul> </div> </div> </nav> </header> <nav class="left-nav shadow d-none d-lg-block"> <div class="list-group list-group-flush"> <a href="index.html" class="list-group-item list-group-item-action active"><i class="fas fa-tachometer-alt"></i> DASHBOARD</a> <a href="users.html" class="list-group-item list-group-item-action"><i class="fas fa-id-card-alt"></i> ユーザ管理</a> <a href="depts.html" class="list-group-item list-group-item-action"><i class="far fa-building"></i> 部署管理</a> </div> </nav> <main class="contents"> <section class="container-fluid"> <header> <h1><i class="fas fa-tachometer-alt"></i> DASHBOARD</h1> </header> <div class="row"> <div class="col-lg mb-3 scale-in"> <div class="card shadow-sm"> <div class="card-body text-center"> <h3>ユーザ登録数</h3> <p class="display-3 userEntry">0</p> </div> </div> </div> <div class="col-lg mb-3 scale-in"> <div class="card shadow-sm"> <div class="card-body text-center"> <h3>部署登録数</h3> <p class="display-3 deptEntry">0</p> </div> </div> </div> </div> <div class="row"> <div class="col-lg mb-3"> <div class="card shadow-sm"> <div class="card-body"> <div id="users"></div> </div> </div> </div> <div class="col-lg mb-3"> <div class="card shadow-sm"> <div class="card-body"> <div id="depts"></div> </div> </div> </div> </div> </section> </main> <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/apexcharts"></script> <script src="assets/js/script.js"></script> <script> $(function(){ /* ログインチェック */ isSignin(); /* processはDashbord */ $process('Dashboard'); /* methodはDashboard.php#getUserEntry */ $method('getUsersEntry'); /* validationなしの非同期通信実行 */ $xhrNoValidate([], function(data, status, xhr){ /* 戻り値は、dataにjsonが入るため、list.rsをキーに取得します。 */ var rs = data.list.rs; /* カウントアップの要素、数、時間(ミリ秒)を渡して実行します。 */ countUp($('.userEntry'), rs.count, 2500); }); /* methodはDashboard.php#getDeptEntry */ $method('getDeptsEntry'); $xhrNoValidate([], function(data, status, xhr){ /* 戻り値は、dataにjsonが入るため、list.rsをキーに取得します。 */ var rs = data.list.rs; /* カウントアップの要素、数、時間(ミリ秒)を渡して実行します。 */ countUp($('.deptEntry'), rs.count, 2500); }); /* グラフの描画設定 */ var options = { series: [], noData: { /* データ取得中の表示文字 */ text: 'Loading...' }, chart: { height: 450, type: 'line', zoom: { enabled: false } }, dataLabels: { enabled: false }, stroke: { curve: 'straight' }, title: { text: 'ユーザ登録推移', align: 'left' }, grid: { row: { colors: ['#efefef', 'transparent'], opacity: 0.05 }, }, xaxis: { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], } }; /* グラフを描画する要素を取得し、グラフを描画 */ var uchart = new ApexCharts(document.querySelector('#users'), options); uchart.render(); /* methodはDashboard.php#getUsersTransitionなので、getUsersTransitionを設定 */ $method('getUsersTransition'); /* 非同期通信を実行 */ $xhrNoValidate([], function(data, status, xhr){ /* データの配列はlist.rsに格納されている */ var rs = data.list.rs; /* updateSeriesを実行すると、そのままデータが反映され描画されます */ uchart.updateSeries([{ name: "ユーザ登録数", data: rs }]) }); /* グラフの描画設定 */ var options = { series: [], noData: { text: 'Loading...' }, chart: { height: 450, type: 'line', zoom: { enabled: false } }, dataLabels: { enabled: false }, stroke: { curve: 'straight' }, title: { text: '部署登録推移', align: 'left' }, grid: { row: { colors: ['#efefef', 'transparent'], // takes an array which will be repeated on columns opacity: 0.05 }, }, xaxis: { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], } }; /* グラフを描画する要素を取得し、グラフを描画 */ var dchart = new ApexCharts(document.querySelector('#depts'), options); dchart.render(); /* methodはDashboard.php#getDeptsTransitionなので、getDeptsTransitionを設定 */ $method('getDeptsTransition'); /* 非同期通信を実行 */ $xhrNoValidate([], function(data, status, xhr){ /* データの配列はlist.rsに格納されている */ var rs = data.list.rs; /* updateSeriesを実行すると、そのままデータが反映され描画されます */ dchart.updateSeries([{ name: "部署登録数", data: rs }]) }); }); </script> </body> </html>
な、長いですね。次回以降は、部署管理からユーザ管理と各機能の実装を行っていきます。