Vue.js + SVG + Firebase とIoT機器で社長の顔色と社内スケジュールを可視化する


課題と作ったもの

sumibi-yakitori です。普段は Nintendo Switch1 でアクションゲームを開発しています。

私の現在の勤務先では、規模が小さいこともあり、Redmineやカンバン系タスク管理ツールをあまり使うことが多くなく、
Google カレンダーで従業員のスケジュールが管理されているのですが、

このように、社員数が増えていくに連れ可読性が下がっています。
もう少し規模が大きくなれば部署ごとに分けるか、別のツールを導入することになるでしょう。

しかし、以前別の職場で中規模プロジェクトをマネジメントしていた頃から、メンバーのタスクをもっと可視化できたらなと考えていました。
更に、私は弊社代表のデスクにゆく頻度が高いのですが、そのたびに顔色を伺うのもボトルネックの一つとして感じていました。
顔色もリモートで確認したい。

そのため以下のようなSPAを作ってみました。

座席表をベースにしたビューに、Googleカレンダーから引いてきたタスクを、直近のものから濃い色、象徴的な色で表示しています。

各クライアントごとに Calendar API を叩くのは避けたかったので、Firebase RDB(VueFire) を使ってビューをリフレッシュすることなくリアルタイムで更新するようにしてあります。

更に弊社代表のデスクには顔色ステータスを表示、ダメ押しに画像の左端にある Philips Hue も使ってオフィス全体に周知します。
(画像では炎上していますが別に激怒しているわけではなく忙しいので話しかけないでほしいという意思表示です)
このステータスの変更には写真左下にあるMESHタグのボタンを使用します。

Vue + SVG

制作にあたって、何で作るかを考えました。しかも座席表のようなUIです。
このような形状の UI は、Unity などを使うのが早いと思いましたが、利便性が何よりも大事なものを重いゲームエンジンで実装するのには強い抵抗がありました。
各OS固有のネイティブアプリを作るのも面倒です。

幸い以前 Vue をとあるSNSを作るためにそれなりの期間使っていたことがありましたので、SPA として作成することにしました。
Vue そのものは良いのですが、私は Web の、しかもフロントエンドエンジニアというわけではないので、
HTML で自由座標の UI を構成するスマートなやり方を知りません。
とにかく迅速に作りたかったので、SVGを使ってみることにしました。

まずは vue init webpack <project-name> でひな型をつくり、

ButtonComponent.vue
<template>
  <svg
    :x="x"
    :y="y"
    :width="width"
    :height="height"
  >
    <g @click="onClick" transform="translate(0, 0)">
      <rect
        x="0"
        y="0"
        :width="width"
        :height="height"
        :stroke="fillColor"
        stroke-width="10"
      >
      </rect>

      <rect
        x="0"
        y="0"
        :width="width"
        :height="height"
        stroke="#000000"
        stroke-width="3"
      >
      </rect>
      <text
        font-size="18"
        font-weight="300"
        fill="#000000"
      >
        <tspan
          x="50%"
          y="55%"
          alignment-baseline="middle"
          text-anchor="middle"
        >
          <slot>BUTTON</slot>
        </tspan>
      </text>
    </g>
  </svg>
</template>
<script>
export default {
  methods: {
    onClick(event) {
      this.$emit('event-on-click');
    },
  },
  computed: { },
  props: {
    x: {
      type: Number,
      default: 0,
    },
    y: {
      type: Number,
      default: 0,
    },
    width: {
      type: Number,
      default: 80,
    },
    height: {
      type: Number,
      default: 40,
    },

    borderColor: {
      type: String,
      default: '#000000',
    },
    fillColor: {
      type: String,
      default: '#000000',
    },
  },
};
</script>

このようなボタンコンポーネントを作り、親コンポーネントのSVGタグ内から利用する形で実装しています。
SVG要素の中でもバインディングが効き、非常に楽に実装することができます。

一点気づいたこととして、<img> タグを使う場合でもローダーを使う場合でも、SVGファイルに外部化したものを読み込む形ではバインディングが使えなかったことです。

IoT機器類

前々から気になっていた SONY の MESH タグを利用しました。
このようなコードを作ります。Meshはコードのエクスポートができないようなので画像を貼ります。

ボタンを押すごとに顔色ステータスが

  • 0: 空席(無色)
  • 1: 在籍中(青色)
  • 2: 仕事してる(黄色)
  • 3: とても忙しい(赤色)

と変化していきます。

各要素の意味は以下のとおりです。

  • ボタンタグ: デスクからステータスを変更する
  • LEDタグ: デスク側でステータスを確認できる
  • Philips Hue: オフィスの中央に置きステータスを確認できる
  • IFTTT: ステータスを Firebase RDB に PUT する

LEDタグは点灯時間を無限に設定できないため、タイマーで連続点灯させています。

運用

作ってみて、わりと便利です。
特に SPA なので、モニターには FireTV Stick のようなブラウザだけが表示できる端末でも稼働できるところが嬉しいです。
弊社の今の規模ですと1フロアで従業員スペースが収まっていますが、そうでない場合は更に便利になるでしょう。