ExcelをHTML5Canvasに描画するお話

こんにちは、小西です。

FLECTではExcelをWebブラウザ上に描画する技術(Excel2Canvas)を開発しており、そのサンプルアプリケーションを公開していますが、この技術は非常に応用範囲の広いものだと考えています。
その応用例のひとつとして現在Evernoteで行われているプログラミングコンテスト(DEVCUP)にEvernoteに添付したExcelファイルをブラウザ上でインラインに表示/共有できるアプリを出品しています。

http://devcup.evernote.com/submissions/8567-excelnote

元々はExcel2Canvasを何に使おうかなということを考えていた段階でたまたまEvernoteでDEVCUPをやっていることに気がついて、じゃこれに出してみようかと軽い気持ちで作成したものです。
なので準備期間も短く、ドメインもherokuappのままなのでどうかとは思いますが実用性は実はエントリ作品の中でもかなり高いほうなんじゃないかと思っています。(ちなみにDEVCUPへの出品自体は個人活動ですが、heroku上で動作するアプリケーションやAddOnがどの程度使えるかを検証することは業務です。)

現在絶賛一般投票中なので、もしよろしければ左上のVoteボタンをクリックしてやってください。(^^;
1日に1回投票できるので毎日投票してくれても良いです。(^^;;;

これだけではなんなので今日はExcel2Canvasが中でどういうことをやっているかについて解説してみたいと思います。

★サーバーサイド

サーバーサイドではApache POIを使ってExcelの情報を抜き出しています。
取得する情報は以下の4つに分解しています。

背景色情報
  - セルの背景色
  - 網掛けなどのパターン種別
  - パターンの色

罫線情報
  - セルの4辺のどこに罫線が引かれているか
  - 罫線の種別(太線、ダッシュ線など)
  - 罫線の色

画像情報
  - 添付されている画像(jpeg,png)のバイナリとその位置

文字(セル)情報
  - 書式設定を適用したセルの値(計算式の場合はその計算結果)
  - 右寄せ、左寄せなどの位置情報
  - フォントと文字装飾と色
  - セルの結合情報

これら4種の情報をひとつのJSONにまとめてクライアントに返しています。

★クライアントサイド

クライアント側ではサーバーから返された情報をCanvasに描画しています。
具体的には以下の順序で処理を行っています。

1、背景色情報でCanvasを塗りつぶし
2、罫線情報でラインを引く
3、画像情報をimgタグでCanvas上に絶対位置で配置
4、文字情報をセルごとにdivタグにして絶対位置で配置

右寄せや左寄せなどのセル内での位置はそれぞれCSSでclass定義しています。

ちなみに背景色や罫線は現時点ではサーバー側から情報は取れていてもすべてを描画はしていません。
たとえば背景色の場合現在行っているのは単色での塗りつぶしのみでパターンの描画はしていません。
もちろん網掛けなんかは自分で少しずつ位置をずらしながらlineToを繰り返せば描画できるわけですが、Excelのサポートする描画パターンを調べ上げてそれに一つずつ対応するというのはさすがにちょっと。。。。めんどくさいんですよ!(言っちゃった。。。(--)
同様に罫線についても長線・短線・短線のような3組で1パターンとなるような線種については未実装です。(シンプルな単線になります。)

若干言い訳くさいですが、サポートするパターンが増えればそれだけjsファイルは肥大化するので、いずれにせよどこかでこういう線引きは必要です。
(もちろん使用頻度の高そうなものを今後実装するのはやぶさかではありません。)

以上、実際には罫線の情報をある程度まとめたり、セルをはみだした長い文字列を結合したりなどの最適化処理も行っていますが、基本的にはこれだけです。

★POIの話

POIのAPIドキュメントを見ると上に挙げた情報はAPIで普通に取れそうに見えます。まぁもちろんそう思ったからこそ作り始めたわけですし、実際最初のプロトを作るまでには2日とかかりませんでした。
が、実際にはそこから先が茨の道です。

以下いくつかはまりどころをあげてみます。

色の取得の仕方がxlsとxlsxで異なる

背景などの色の持ち方はxlsの場合IndexedColorと言って「1番は何色、2番は何色」というようにワークブックごとに番号と色の対応が決まっています。
一方xlsxの場合はIndexedColorの他にRGBでの指定やテーマでの色指定など複数のデータの持ち方があります。
が、POIのxls/xlsx共通インターフェースから取得できるのは多くの場合IndexedColorだけなのでxlsxの場合はキャストして専用APIを使用して色を取得する必要があります。
(ちなみにテーマを使用した場合の色の取得方法がMSのドキュメントを見てもどうしてもわからなかったので現在未対応です。)

日本語日付書式全滅

Excelでは内部的に日付データはDoubleで持っており、どんなライブラリを使用する場合でも日付の扱いは鬼門となるんですが、POIでの日本語日付の扱いはお話にならない位ひどいです。(--
仕方がないので

http://support.microsoft.com/kb/883199/ja

を参考に日付書式のパーサーを全部自分で書き直しましたが、今度は逆に日本語以外の書式設定が正しく扱えていないのではないかという不安はあります。

列幅の計算がやっかい

Excelではセルの列幅を「デフォルトフォントの文字何個分」というデータの持ち方をしています。例えば日本語版Excelの場合は初期状態で列幅は「8.38」となっていますが、これは「MS Pゴシック11ptで数字が8.38文字収まる幅」という意味です。
英語版Excelの場合はデフォルトフォントは(おそらく)Arial10ptなので、同じ数字であってもセル幅は異なります。
しかもデフォルトフォントからセル幅を計算する方法も結局地道に実測して割り出したので非常に面倒です。(GraphicsContextに描画してstringWidthを取るという方法も試しましたが、結局微妙な幅があわずにあきらめました。)

現状対応しているデフォルトフォントは「MS Pゴシック11pt」と「Arial10pt」のみなのでそれ以外をデフォルトフォントとするファイルがある場合はセル幅が微妙にずれるはずです。(--

計算式がどの程度サポートされているのか謎

何故かWeekday関数がサポートされていなかったり。。。
Subtotal関数がものすごく根本的なところでバグっていたり。。。
と正直計算式がどの程度ちゃんと動くのかは未知数です。
直せるところは自分で直したりPOIにバグレポをあげたりもしていますが、おそらくこの辺りはPOIの中でもあまりたたかれていない部分のような気がするので他にも色々と問題はありそうです。

などなど。
他にもいっぱいありますが、それ以外にもまだ気がついていない問題もたくさんあるだろうとは思っています。

★Excel2Canvasの今後

FLECTの主業務はSIなのでとりあえずはその方向での活用していくことになります。具体的なターゲットとしてはまず帳票を考えていて、Excelで作成した帳票フォーマットがそのままブラウザで表示できてさらにブラウザから印刷までできるとなるとかなりニーズはありそうです。

Excel2Canvas自体の機能としては今後、グラフや条件付き書式に対応できると良いなと思っていますが時期は未定です。また、それらは対応するとしてもおそらくxlsxのみの対応となります。(POIにはそれらを取得するためのAPIがないので、ooxmlから直で情報を取得することになるからです。)

グラフは一度トライしかけたんですが、そもそもExcelで思ったとおりのグラフを作ることができなくてコードを書く以前のところで挫折しました。(^^;;;

正直その辺まで来ると自分ひとりの手には余ると思っていて、オープンソース化なども検討していますが、当面そのための作業の優先順位は低いです。

コメント(0)