multiple line chart で時刻を縦軸に取る実装方法(d3.js)

Tech, 作ってみたd3.js


はじめに

はじめに

現在、私は入江開発室という、開発者の集まるオンラインサロン(?)に所属しています。
サロンにはSlackチームがあって、その中に # 朝活で自分の時間をつくろう という名前の、朝早起きしたらメッセージを投稿するchannelがあります。

Slackの様子

基本的に「おはようございます!」と投稿するだけですが、不思議と 朝起きるための力をもらえるようなchannelです。

私はこのchannelをとても気に入っているので、早起き人口を増やすためにも、このchannelの動向を可視化するためのwebアプリを作りはじめました。

作っているアプリ

アプリのイメージ

このアプリでは、

  • 縦軸 = メッセージ投稿時刻
  • 横軸 = 直近2週間の日付

の二軸に対してSlackのメッセージとユーザー情報を紐づけマッピングしています。
マウスオーバーするとメッセージが表示されます。

触ってみたい人はこちら↓
morning | 朝活を応援

縦軸を時刻にする

早速ですが、タイトルに記載した実装方法を紹介します。
全体のコードが見たい方はGithub からどうぞ。

対象データ


[ { "id": 10, "user": "UE03YQ20H", "realName": "Kyogo Mochida", "image24": "https://avatars.slack-edge.com/2019-01-15/523494664179_c52030a5a9f22b1393b8_24.png", "text": "おはようございます!", "msPass": 75988227, "date": "2019-02-07T15:00:00.000Z" }, { "id": 19, "user": "UE03YQ20H", "realName": "Kyogo Mochida", "image24": "https://avatars.slack-edge.com/2019-01-15/523494664179_c52030a5a9f22b1393b8_24.png", "text": "おはようございます!寝坊した...", "msPass": 79603223, "date": "2019-02-05T15:00:00.000Z" }, { "id": 27, "user": "UE03YQ20H", "realName": "Kyogo Mochida", "image24": "https://avatars.slack-edge.com/2019-01-15/523494664179_c52030a5a9f22b1393b8_24.png", "text": "おはようございます", "msPass": 75439218, "date": "2019-02-04T15:00:00.000Z" } ]

各プロパティの説明

  • id … データ1件のユニークなID
  • user… SlackのユーザーID
  • realName…Slackのユーザー名
  • image24…Slackのユーザーアイコン
  • text…メッセージ内容
  • msPass…メッセージの投稿時刻(ミリ秒単位)
  • date…メッセージの投稿日

今回は、
msPassdate だけ気にしていればokです。
msPassはY軸、dateはX軸になります。

msPassは、サーバーサイド(Node.js)で、やや複雑な加工をしているので説明します。

Slack APIを利用してメッセージを取得すると、
レスポンスの形式は下記のようになります。


{ "client_msg_id": "64431F4D-960B-4EB3-8ABF-58D14D26C93E", "type": "message", "text": "おはようございます!", "user": "UBBJW8MNV", "ts": "1549747882.003100" },

このtsがmsPassの元になります。
tsは、UNIXTIMESTAP(秒単位)です。

なので、 tsに1日の秒数を剰余演算することで、00:00からの経過時間を取得することができます。(分かりにくいので下の図で説明)

剰余演算

Y軸となるmsPassが上記によって求められたらあとは簡単です。
d3のScaleTime で時刻に変換して表示しましょう


const objY = 'msPass'; const yScale: ScaleTime<number, number> = d3.scaleTime(); yScale.domain(d3.extent(data, (d) => +d[objY])); yScale.range([margins.top, height - margins.bottom]) const yAxis: Axis<{}> = d3.axisLeft(yScale);

Githubでソースコード全文を見る

Tech, 作ってみたd3.js

Posted by kyogom