入社3年目、Webエンジニアの今村です。
主な仕事内容としては、弊社が販売しているサービス「現場クラウドConne」の開発を行っております。
今回は、私が入社2年目の夏に行っていた「ダッシュボードアプリ開発」で悪戦苦闘した話をご紹介します。
やりたかったこと
- 社内のカスタマーサクセスチームがConneの利用状況を把握するためのダッシュボード作成。
※Conne→建設業に関わる方向けのコミュニケーションツール
https://conne.genbasupport.com - kintoneで作成したダッシュボードアプリ上に、Conneが持つ各種指標を日、週、月単位で登録。
※kintone→https://kintone.cybozu.co.jp/ - ダッシュボードアプリとその他の連携させたいアプリからレコードを取得し、グラフで表示。
- 組織や日付を切り替えたら、その条件で各グラフを再描画
先に完成した画面を載せておきます。
※情報を伏せる為、一部ぼかしてあります。
アプリの構成
構成は以上のようになっていて、
今回私が行ったのは、ダッシュボードアプリ内の連携とグラフ描画の部分になります。
主に以下の処理をJavaScriptで実装しました。
- kintone APIでレコード情報を取得
- 取得した情報を表示したいグラフに合わせて整形
- chart.jsでグラフを描画
chart.jsについて
使用したJavaScriptライブラリ「chart.js」の使い方について、解説していきます。
下に、今回作成したグラフの中から一部抜粋したコードを掲載します。
//データの準備 function createTotalUsersCount(fromDate, toDate, offset) { var data = { dates: [], userCounts: [], guestCounts: [] } requestBody = { "app": DB_APP_ID, "totalCount": true, "fields": ["日付", "組織ユーザー総数", "ゲスト総数"], 'query': 'レコードタイプ in ("日次") and 日付 >= "' + fromDate + '" and 日付 <= "' + toDate + '" order by 日付 asc offset ' + offset }; kintone.api(kintone.api.url('/k/v1/records', true), 'GET', requestBody, function(resp) { resp.records.forEach(function(record, i){ data.dates.push(record["日付"].value); data.userCounts.push(record["組織ユーザー総数"].value); data.guestCounts.push(record["ゲスト総数"].value); }); // GET数制限対応 if(resp.records.length == 100){ offset += 100; createTotalUsersCount(fromDate, toDate, offset); }else{ drawTotalUsersCount(data); } }, function(error) { // 失敗したときの処理 console.log(error); }); } // グラフ描画 function drawTotalUsersCount(data){ var ctx = document.getElementById("total-users-canvas").getContext("2d"); // 再表示する際、グラフのインスタンスを破棄する if(totalUsersCountGraph){ totalUsersCountGraph.destroy(); } // 設定 var config = { type: "line", data: { labels: data.dates, datasets: [ { label: "組織ユーザー", data: data.userCounts, borderColor: "rgba(254,97,132,0.5)", backgroundColor: "rgba(0,0,0,0)" },{ label: "ゲストユーザー", data: data.guestCounts, borderColor: "rgba(54,164,235,0.5)", backgroundColor: "rgba(0,0,0,0)" } ] }, options: { responsive: true, title: { display: true, fontSize: 18, text: '総ユーザー数' }, tooltips: { mode: 'x-axis', position: 'average', bodyFontSize: 14, }, scales: { yAxes: [{ ticks: { beginAtZero: true, min: 0 } }] } } }; window.totalUsersCountGraph = new Chart(ctx, config); }
前半の関数でdataを用意し、それを引数に渡して描画関数を実行します。
描画関数の最終行で new Chart() に、「どこに描画するか、どんなグラフにするか」
という情報を与えて描画処理を行っています。
肝となる「どんなグラフにするか」の部分は config という変数名で渡しているので、その中身を見ていきます。
config では 以下3つの設定を行います。
- type (グラフの形式)
- data (縦軸、横軸の値)
- options (各種設定)
今回は type は折れ線グラフなので “line”
data.labels は横軸なので日付
data.datasets は配列になっていて、集計結果を複数表示させることもできます。
data.datasets[i].data に、整形したデータを入れています。
それに応じて縦軸の数字は自動で入ってくれますが、 options.scales でさらにその辺の細かい設定ができます。
options では他にも、タイトルのフォントや位置、ツールチップに関する設定など行うことができます。
他にも色々設定できるようですので、詳細は公式ドキュメントをご覧ください。
日本語版もあるようです。
https://misc.0o0o.org/chartjs-doc-ja/
大変だったこと
設計面
依頼者との認識合わせが思っていたより大変で、しかしとても大切だと感じました。
アプリ開発前後でそれぞれ以下の認識を合わせていました。
開発前…要望をみて疑問点を質問し、解消しながら設計に落としていく
開発後…使用したデータの説明や計算式をまとめて共有
特に、開発後に行った計算式等の共有は、
- 要望通りのデータが集計できているのかどうかわからない
- 今の仕様を確認できない
といった状況を防ぐために行いました。
しかし、本来であれば、設計に落とした段階で共有しておくべだったと反省しています。
今回は社内からの依頼でしたが、今後同じような機会があった際には、社内でも社外でも活かしていきたいと思います。
技術面
今回は特に難しい技術を使っているわけでは無かったので、時間はかかりましたが、調べながら自力で8割方進められました。
その中で躓いたのは以下の点でした。
- jQuery
$ is not defined
$(…).datepicker is not a function
といったエラーに何度も会いました
読み込む順番や書き方がおかしくないか、複数回読み込んでいないか、等
一つ一つおかしいところを探して修正を行っていましたが、ここには結構時間を使ってしまいました。 - kintone API
1度に取得できるレコード数が100件までという制限があったので、それ以上取得したい場合は、再帰的に「次の100件を取得する」処理を書かなければなりません。
上に載せたコードの「// GET数制限対応」で書いていますが、初めはここの書き方が慣れなかったです。
開発を終えて
今回kintoneで開発するに至った経緯として、
- 社内の皆がkintoneを使い慣れていて、誰でも閲覧できること
- kintoneのグラフ機能を活用すれば、低い開発コストで実現できそうだったこと
があります。
しかし、kintoneのグラフ機能では、今回の要望を全て満たすことが難しく、
今回紹介したような、Chart.jsを使って実装する作りになりました。
その結果として、今回開発した部分においてkintoneの機能を全く使わない作りになってしまいました。
さらに、kintoneを使うことで以下のような課題もあるため、kintoneを使わない新たな構成を検討したいと思っています。
- 同じプログラムを使いまわしづらい
- 開発、保守にkintoneの知識が必要となり、属人化につながる
- 今後レコードが膨大になったとき、パフォーマンス低下の可能性がある
- kintoneAPIの制限に引っかかる可能性がある。
今後、このダッシュボードアプリを他の自社サービスにも展開していけるよう、汎用性、保守性を高め、より使いやすいものにしていきたいと思います。