freee社宅管理でSVGを使ってシミュレータ描画を行った話

はじめに

はじめまして、金融や新規事業系の開発を行っている部署でエンジニアをしている id:ymizushi です。

普段は、バイクでイカを釣りに行ったり、Splatoon2でXパワー2500以上になるべくイカへのキル意識を高めた立ち回り研究をしたり等、日々イカした生活を送っています。

今年4月に入社したのですが、もう半年以上経っているんですね... 時の流れの速さに流されないように、頑張っていきたいものです。

さて、このエントリーは、freee Developers Advent Calendar 2019 7日目の記事になります。

adventar.org

freee社宅管理

つい先日、freee 社宅管理 というサービスのランディングページを公開しましたが、このランディングページでは 社会保険料の変動額や手取り増加効果を補助金額、月額給与、利用人数などを入力することでシミュレートする機能があります。

www.freee.co.jp

このシミュレーターを実装するに当たり、React + SVG で描画を行いましたが、本エントリーではざっくりとしたSVG+Reactの採用経緯、SVGの概要、SVG+Reactの簡単なチュートリアルについて記述していこうと思います。

React + SVG を採用した経緯

シミュレータの実装、ランディングページ、問い合わせページ、問い合わせ完了ページ、効果計測など、すべての開発期間が8営業日ほどしかなく、シミュレータ自体の実装開発に取れる期間も3日ほどしかありませんでした。

そのため、元々は HiCharts などの チャートライブラリを使用してシミュレーターを実装することを考えていました。

しかし、手取り増加効果や社会保険料変動額を如何にわかりやすくユーザーに提示するかという観点で作られるUX/UIと、既存のチャートライブラリで実現できることに乖離がある状態でした。

以前、 asobiba 2019 というイベント当日限定で使用できたとあるシミュレーターの開発で既に SVG + React での描画をある程度経験しており、また座標計算もそれほど高度なことはなく、メイン機能も2日ほどで実装出来る感触があったため、今回 React + SVG で自前でシミュレータ描画を行なうことにしました。

SVGとは

まず、SVG*1 について簡単に説明させていただきます。

SVGは、Scalable Vector Graphics の略で、名前が表す通りベクターグラフィックス*2を表現するためのXMLのアプリケーション*3です。

先述したとおり、SVGはXMLで表現されているため、他のバイナリフォーマットのベクターグラフィックスと違って、人間にも構造が理解しやすく、テキストで直接編集することも容易です。

SVG については 仕様が Scalable Vector Graphics (SVG) 1.1 (Second Edition) で公開されており、日本語訳も SVG 1.1 仕様 (第2版) 日本語訳 で参照できます。

また、解説についても、 Webであれば SVG: Scalable Vector Graphics | MDN や、書籍であれば O'Reilly Japan - SVGエッセンシャルズ 第2版 などの素晴らしいドキュメントが多数存在します。

SVGをWebで採用するに当たり気になるのがブラウザのサポート状況ですが、一部の属性を除きほぼすべてのモバイルを含むモダンブラウザで対応されていますので、一般的なWebサービスにおいて問題になることは稀だと思われます。

SVGの各仕様については、以下の章で React + SVGでヒートマップを実装するというチュートリアルを用意しているので、そのチュートリアルをこなす上で必要な最低限のSVG仕様を解説する、という方針で進めていこうと思います。

SVG + React チュートリアル

SVGはXMLであり、また動的なDOM書き換えを仕様でサポートしているため、SVG要素をそのまま Reactコンポーネント化することが可能です。 チャートなどの描画では設定した初期座標とコンポーネントに入力された propsから描画対象の座標を計算するロジックを組む必要があります。

今回のfreee 社宅管理 では、UXデザイナーに作成してもらったデザインをベースに初期座標や入力値に基づいて、描画で必要となる座標計算を行いましたが、このチュートリアルではヒートマップを描画することを題材に、SVG + React でのチャート描画について解説していこうと思います。

最終的なチュートリアルの成果物は、 github.com というリポジトリで公開しています。

表現するものを決める

今回のチュートリアルでは、 https://user-images.githubusercontent.com/788785/70264296-80899b80-17db-11ea-8384-b9b1aa3e1449.png のようなヒートマップを描画します。

上記を実現するために、まずは機能として必要なものを列挙してみます。*4

  • ヒートマップはReactコンポーネントとして再利用できる
  • ヒートマップ内ではローカル座標系で描画し、コンポーネントを利用する際に topleftmargin を設定できる
  • ヒートマップのdataは number[][] 型として表現する
  • ヒートマップの行数と列数はヒートマップの data から自動算出する
  • ヒートマップコンポーネントに対して datamax を設定できる

上記を満たすインターフェースとして、以下のように利用できるコンポーネントを考えてみました。

<Heatmap
  margin={{top: 10, left: 10}}
  size={{width: 100, height: 200}}
  data={[[10,10,10,5,10],[12,12,13,4,12]]}
  max={50}
/>

上記の仕様を満たすコンポーネントを実装していきます。

コンポーネントを実装する

github.com

コンポーネントの実装詳細や手順については上記プルリクエストで解説しています。

おわりに

freee社宅管理でSVGを使ってシミュレータ描画を行った件について、チュートリアルなどを交えつつ説明してみましたが、いかがだったでしょうか。

ちなみに個人的に嬉しかったこととして、SVGを書いていくうちに、簡単なアイコンは自分で手書きで書いて自分でスタイルを当てられるようになったことです。 ➕ や ➖ などのアイコン、▲の部品なども、デザインをベースに今回はすべて手書きSVG+CSS で作成しました。

SVGで図形を描画することにより、ブラウザのデベロッパーツールで動的に線分の太さや色を修正することが出来ます。 これによりUXデザイナーと画面をみつつ動的にスタイル調整などが出来るため、SVGでクリエイティブを描画する大きなメリットではないかと思います。

しかし、改善点もあります。

今回、UXデザイナーと一緒に作業をやる上でボトルネックと感じたところは、座標計算の修正でした。 描画する座標はプログラムで計算しているため、例えばツールチップの横幅を長くしたい、といった作業の際にもエンジニアがコードを編集する必要がありました。 解決策としては、例えば ベクターグラフィックスの編集ツール上で、変数の設定が出来たり、ドローイングツールでその変数を参照出来たり、それをReactコンポーネントとして書き出しプログラム側で自動で取り込む機能があれば、UXデザイナーがエンジニアを介在せずに自由にレイアウトを変更出来るようになるのではないかと思います。

既存のツールも探してみましたが、現状では上記のワークフローを実現することが難しいと判断しており、これは自分で実装していくしかないなと考えています。上記のワークフロー改善については進捗あればまた別途情報共有していきたいと考えています。

freee Developers Advent Calendar 2019 7日目の記事 は以上となります。

明日は、id:mihyaeru21 さんです、よろしくおねがいします!

*1:1.1 , 2.0 などのバージョンがありますが、ここでは 1.1を前提とします

*2:ベクターグラフィックスは、線分や四角などの幾何学表現の集合として表現されます。これに対する概念がビットマップなどのラスターグラフィックスです

*3:ここは教科書どおりの表現になっていますが、要するにベクターグラフィックスの表現するためにXMLを使っているということ

*4:ヒートマップを実装する前に手書きで作ったスケッチがあるが、最終的なコードでの成果物の方が見栄えがよかったため、順番としては逆になってしまうがこちらを完成イメージとして採用した