入社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の制限に引っかかる可能性がある。
 
今後、このダッシュボードアプリを他の自社サービスにも展開していけるよう、汎用性、保守性を高め、より使いやすいものにしていきたいと思います。