Excel2 canvas

20
Excel2Canvas 2013/04/04 株株株株 FLECT 株株 西

description

Excelをブラウザで表示する

Transcript of Excel2 canvas

Page 1: Excel2 canvas

Excel2Canvas

2013/04/04株式会社 FLECT

小西俊司

Page 2: Excel2 canvas

Excel シートを Web ブラウザ上に描画するライブラリ◦ https://github.com/shunjikonishi/excel2canvas

罫線や背景色は HTML5 の Canvas 上に描画◦ なので IE8 以前の古いブラウザでは動きません◦ 動作確認は一応 Chrome, Firefox, IE9, Safari, iOS,

Android でしてます。 特に何か目的を持って作ったものではな

く、 Canvas の調査時になんとなく思いつきで試してみたのが始まり◦ 絵心があったら多分こんなものは作ってない。。。

Excel2Canvas とは

Page 3: Excel2 canvas

ネットで拾ったものを少し加工したサンプル( 記憶が確かなら一番最初のテストデータ )

思った以上に Excel で作ったレイアウトを再現できてる

ちなみに印刷もこのままでます

さりげなく画像 ( 左上のロゴ ) とリンクもサポート

請求書のサンプル

Page 4: Excel2 canvas

グラフも部分的にサポート

棒グラフや円グラフなどの単純なグラフのみ

細かいプロパティ設定は全部無視するので見た目は Excel と同じにはならない

グラフの描画に使用しているライブラリは Flotr2

グラフもいけたり

Page 5: Excel2 canvas

まず Java 側で◦ Apache POI で Excel ファイルの情報を読み取り◦ それを JSON 化

次に JavaScript で◦ キャンバスに罫線と背景を描画して◦ 文字列はセル毎に div タグで絶対位置に配置◦ その上に画像とグラフを重ねて完成

とても泥臭い

どういうアーキテクチャ?

Page 6: Excel2 canvas

ExcelToCanvasBuilder を作って Excel ファイルを渡してやれば OK

使い方 - JavaExcelToCanvasBuilder builder = new ExcelToCanvasBuilder(); builder.setIncludeComment(true);// コメント情報を含める builder.setIncludeChart(true);// グラフ情報を含めるbuilder.setIncludePicture(true);// 画像情報を含めるString json = builder.build(new File("Book1.xlsx"), "Sheet1").toJson();

Page 7: Excel2 canvas

{"width":1035,"height":872,"lines":[{"p":[702,0,963,0],"kind":2},{"p":[0,32,224,32],"kind":6},{"p":[702,32,963,32],"kind":2},{"p":[0,52,688,52],"kind":2},{"p":[702,52,963,52]},{"p":[0,70,688,70]},{"p":[702,70,963,70]},{"p":[702,88,963,88]},{"p":[0,106,688,106]},{"p":[702,106,963,106]},{"p":[0,125,688,125],"kind":2},{"p":[702,125,963,125]},{"p":[702,143,963,143]},{"p":[0,162,688,162],"kind":2},{"p":[702,162,963,162]},{"p":[0,180,688,180]},{"p":[702,180,963,180]},{"p":[702,198,963,198]},{"p":[0,216,688,216]},{"p":[702,216,963,216]},{"p":[0,235,688,235],"kind":2},{"p":[702,235,963,235]},{"p":[29,254,688,254],"kind":2},{"p":[702,254,963,254]},{"p":[0,273,688,273],"kind":2},{"p":[702,273,963,273]},{"p":[0,291,688,291]},{"p":[702,291,963,291]},{"p":[0,309,688,309]},{"p":[702,309,963,309]},{"p":[0,327,688,327]},{"p":[702,327,963,327]},{"p":[0,345,688,345]},{"p":[702,345,963,345]},{"p":[0,363,688,363]},{"p":[702,363,963,363]},{"p":[0,381,688,381]},{"p":[702,381,963,381]},{"p":[0,399,688,399]},{"p":[702,399,963,399]},{"p":[0,417,688,417]},{"p":[702,417,963,417]},{"p":[0,435,688,435]},{"p":[702,435,963,435]},{"p":[0,453,688,453]},{"p":[702,453,963,453]},{"p":[0,471,688,471]},{"p":[702,471,963,471]},{"p":[0,489,688,489]},{"p":[702,489,963,489]},{"p":[0,507,688,507]},{"p":[702,507,963,507]},{"p":[0,525,688,525]},{"p":[702,525,963,525]},{"p":[0,543,688,543]},{"p":[702,543,963,543]},{"p":[0,561,688,561]},{"p":[702,561,963,561]},{"p":[0,579,688,579]},{"p":[702,579,963,579]},{"p":[0,597,688,597]},{"p":[702,597,963,597]},{"p":[0,615,688,615]},{"p":[702,615,963,615]},{"p":[0,634,688,634],"kind":2},{"p":[702,634,963,634]},{"p":[108,652,688,652]},{"p":[702,652,963,652]},{"p":[108,671,688,671],"kind":2},{"p":[702,671,963,671]},{"p":[108,689,688,689]},{"p":[702,689,963,689]},{"p":[108,708,688,708],"kind":2},{"p":[702,708,963,708]},{"p":[108,727,688,727],"kind":2},{"p":[702,727,963,727]},{"p":[702,745,963,745]},{"p":[702,763,963,763]},{"p":[702,781,963,781]},{"p":[702,799,963,799]},{"p":[702,817,963,817]},{"p":[702,835,963,835]},{"p":[702,854,963,854],"kind":2},{"p":[0,52,0,125],"kind":2},{"p":[0,162,0,235],"kind":2},{"p":[0,273,0,634],"kind":2},{"p":[29,254,29,634],"kind":2},{"p":[108,52,108,125]},{"p":[108,162,108,235]},{"p":[108,254,108,634]},{"p":[108,634,108,727],"kind":2},{"p":[446,254,446,634]},{"p":[488,254,488,634]},{"p":[568,254,568,727]},{"p":[688,52,688,125],"kind":2},{"p":[688,162,688,235],"kind":2},{"p":[688,254,688,727],"kind":2},{"p":[702,0,702,854],"kind":2},{"p":[756,0,756,854]},{"p":[920,0,920,854]},{"p":[963,0,963,854],"kind":2}],"fills":[{"p":[702,0,54,32],"fore":"#C0C0C0"},{"p":[756,0,164,32],"fore":"#C0C0C0"},{"p":[920,0,43,32],"fore":"#C0C0C0"},{"p":[29,254,79,19],"fore":"#969696"},{"p":[108,254,24,19],"fore":"#969696"},{"p":[132,254,92,19],"fore":"#969696"},{"p":[224,254,222,19],"fore":"#969696"},{"p":[446,254,42,19],"fore":"#969696"},{"p":[488,254,80,19],"fore":"#969696"},{"p":[568,254,120,19],"fore":"#969696"},{"p":[0,273,29,18],"fore":"#969696"},{"p":[108,273,24,18],"fore":"#C0C0C0"},{"p":[132,273,92,18],"fore":"#C0C0C0"},{"p":[224,273,222,18],"fore":"#C0C0C0"},{"p":[488,273,80,18],"fore":"#C0C0C0"},{"p":[568,273,120,18],"fore":"#C0C0C0"},{"p":[0,291,29,18],"fore":"#969696"},{"p":[108,291,24,18],"fore":"#C0C0C0"},{"p":[132,291,92,18],"fore":"#C0C0C0"},{"p":[224,291,222,18],"fore":"#C0C0C0"},{"p":[488,291,80,18],"fore":"#C0C0C0"},{"p":[568,291,120,18],"fore":"#C0C0C0"},{"p":[0,309,29,18],"fore":"#969696"},{"p":[108,309,24,18],"fore":"#C0C0C0"},{"p":[132,309,92,18],"fore":"#C0C0C0"},{"p":[224,309,222,18],"fore":"#C0C0C0"},{"p":[488,309,80,18],"fore":"#C0C0C0"},{"p":[568,309,120,18],"fore":"#C0C0C0"},{"p":[0,327,29,18],"fore":"#969696"},{"p":[108,327,24,18],"fore":"#C0C0C0"},{"p":[132,327,92,18],"fore":"#C0C0C0"},{"p":[224,327,222,18],"fore":"#C0C0C0"},{"p":[488,327,80,18],"fore":"#C0C0C0"},{"p":[568,327,120,18],"fore":"#C0C0C0"},{"p":[0,345,29,18],"fore":"#969696"},{"p":[108,345,24,18],"fore":"#C0C0C0"},{"p":[132,345,92,18],"fore":"#C0C0C0"},{"p":[224,345,222,18],"fore":"#C0C0C0"},{"p":[488,345,80,18],"fore":"#C0C0C0"},{"p":[568,345,120,18],"fore":"#C0C0C0"},{"p":[0,363,29,18],"fore":"#969696"},{"p":[108,363,24,18],"fore":"#C0C0C0"},{"p":[132,363,92,18],"fore":"#C0C0C0"},{"p":[224,363,222,18],"fore":"#C0C0C0"},{"p":[488,363,80,18],"fore":"#C0C0C0"},{"p":[568,363,120,18],"fore":"#C0C0C0"},{"p":[0,381,29,18],"fore":"#969696"},{"p":[108,381,24,18],"fore":"#C0C0C0"},{"p":[132,381,92,18],"fore":"#C0C0C0"},{"p":[224,381,222,18],"fore":"#C0C0C0"},{"p":[488,381,80,18],"fore":"#C0C0C0"},{"p":[568,381,120,18],"fore":"#C0C0C0"},{"p":[0,399,29,18],"fore":"#969696"},{"p":[108,399,24,18],"fore":"#C0C0C0"},{"p":[132,399,92,18],"fore":"#C0C0C0"},{"p":[224,399,222,18],"fore":"#C0C0C0"},{"p":[488,399,80,18],"fore":"#C0C0C0"},{"p":[568,399,120,18],"fore":"#C0C0C0"},{"p":[0,417,29,18],"fore":"#969696"},{"p":[108,417,24,18],"fore":"#C0C0C0"},{"p":[132,417,92,18],"fore":"#C0C0C0"},{"p":[224,417,222,18],"fore":"#C0C0C0"},{"p":[488,417,80,18],"fore":"#C0C0C0"},{"p":[568,417,120,18],"fore":"#C0C0C0"},{"p":[0,435,29,18],"fore":"#969696"},{"p":[108,435,24,18],"fore":"#C0C0C0"},{"p":[132,435,92,18],"fore":"#C0C0C0"},{"p":[224,435,222,18],"fore":"#C0C0C0"},{"p":[488,435,80,18],"fore":"#C0C0C0"},{"p":[568,435,120,18],"fore":"#C0C0C0"},{"p":[0,453,29,18],"fore":"#969696"},{"p":[108,453,24,18],"fore":"#C0C0C0"},{"p":[132,453,92,18],"fore":"#C0C0C0"},{"p":[224,453,222,18],"fore":"#C0C0C0"},{"p":[488,453,80,18],"fore":"#C0C0C0"},{"p":[568,453,120,18],"fore":"#C0C0C0"},{"p":[0,471,29,18],"fore":"#969696"},{"p":[108,471,24,18],"fore":"#C0C0C0"},{"p":[132,471,92,18],"fore":"#C0C0C0"},{"p":[224,471,222,18],"fore":"#C0C0C0"},{"p":[488,471,80,18],"fore":"#C0C0C0"},{"p":[568,471,120,18],"fore":"#C0C0C0"},{"p":[0,489,29,18],"fore":"#969696"},{"p":[108,489,24,18],"fore":"#C0C0C0"},{"p":[132,489,92,18],"fore":"#C0C0C0"},{"p":[224,489,222,18],"fore":"#C0C0C0"},{"p":[488,489,80,18],"fore":"#C0C0C0"},{"p":[568,489,120,18],"fore":"#C0C0C0"},{"p":[0,507,29,18],"fore":"#969696"},{"p":[108,507,24,18],"fore":"#C0C0C0"},{"p":[132,507,92,18],"fore":"#C0C0C0"},{"p":[224,507,222,18],"fore":"#C0C0C0"},{"p":[488,507,80,18],"fore":"#C0C0C0"},{"p":[568,507,120,18],"fore":"#C0C0C0"},{"p":[0,525,29,18],"fore":"#969696"},{"p":[108,525,24,18],"fore":"#C0C0C0"},{"p":[132,525,92,18],"fore":"#C0C0C0"},{"p":[224,525,222,18],"fore":"#C0C0C0"},{"p":[488,525,80,18],"fore":"#C0C0C0"},{"p":[568,525,120,18],"fore":"#C0C0C0"},{"p":[0,543,29,18],"fore":"#969696"},{"p":[108,543,24,18],"fore":"#C0C0C0"},{"p":[132,543,92,18],"fore":"#C0C0C0"},{"p":[224,543,222,18],"fore":"#C0C0C0"},{"p":[488,543,80,18],"fore":"#C0C0C0"},{"p":[568,543,120,18],"fore":"#C0C0C0"},{"p":[0,561,29,18],"fore":"#969696"},{"p":[108,561,24,18],"fore":"#C0C0C0"},{"p":[132,561,92,18],"fore":"#C0C0C0"},{"p":[224,561,222,18],"fore":"#C0C0C0"},{"p":[488,561,80,18],"fore":"#C0C0C0"},{"p":[568,561,120,18],"fore":"#C0C0C0"},{"p":[0,579,29,18],"fore":"#969696"},{"p":[108,579,24,18],"fore":"#C0C0C0"},{"p":[132,579,92,18],"fore":"#C0C0C0"},{"p":[224,579,222,18],"fore":"#C0C0C0"},{"p":[488,579,80,18],"fore":"#C0C0C0"},{"p":[568,579,120,18],"fore":"#C0C0C0"},{"p":[0,597,29,18],"fore":"#969696"},{"p":[108,597,24,18],"fore":"#C0C0C0"},{"p":[132,597,92,18],"fore":"#C0C0C0"},{"p":[224,597,222,18],"fore":"#C0C0C0"},{"p":[488,597,80,18],"fore":"#C0C0C0"},{"p":[568,597,120,18],"fore":"#C0C0C0"},{"p":[0,615,29,19],"fore":"#969696"},{"p":[108,615,24,19],"fore":"#C0C0C0"},{"p":[132,615,92,19],"fore":"#C0C0C0"},{"p":[224,615,222,19],"fore":"#C0C0C0"},{"p":[488,615,80,19],"fore":"#C0C0C0"},{"p":[568,615,120,19],"fore":"#C0C0C0"},{"p":[108,671,24,18],"fore":"#C0C0C0"},{"p":[132,671,92,18],"fore":"#C0C0C0"},{"p":[224,671,222,18],"fore":"#C0C0C0"},{"p":[446,671,42,18],"fore":"#C0C0C0"},{"p":[488,671,80,18],"fore":"#C0C0C0"},{"p":[568,671,120,18],"fore":"#C0C0C0"},{"p":[108,708,24,19],"fore":"#969696"},{"p":[132,708,92,19],"fore":"#969696"},{"p":[224,708,222,19],"fore":"#969696"},{"p":[446,708,42,19],"fore":"#969696"},{"p":[488,708,80,19],"fore":"#969696"}],"strs":[{"p":[0,0,224,32],"id":"A1","text":"注 文 書","align":"cb","style":"text-wrap:none;font-size:20pt;font-family:MS Pゴシック;"},{"p":[224,0,464,32],"id":"E1","text":" * 下の注文書に商品コードと数量をご記入、印刷の上、弊社担当セールスに\u003cbr\u003e お渡しいただくか、0xx-xxx-xxxx にファックスにてご送信ください。","align":"lb","style":"font-size:8pt;font-family:MS Pゴシック;"},{"p":[702,0,54,32],"id":"J1","text":"商品\u003cbr\u003eコード","align":"cc","style":"font-size:10pt;font-family:MS Pゴシック;"},{"p":[756,0,164,32],"id":"K1","text":"商品名","align":"cc","style":"text-wrap:none;font-size:10pt;font-family:MS Pゴシック;"},{"p":[920,0,43,32],"id":"L1","text":"価格","align":"cc","style":"text-wrap:none;font-size:10pt;font-family:MS Pゴシック;"},{"p":[702,32,54,20],"id":"J2","text":"001-01","align":"lbg","style":"text-wrap:none;font-size:10pt;font-family:MS Pゴシック;"},…

こんな JSON が返ってきます

Page 8: Excel2 canvas

jQuery プラグインになっているので Canvas を保持するdiv タグで excelToCanvas メソッドを呼び出せば OK

使い方 - JavaScript<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js“ ></script>

<link rel="stylesheet" type="text/css" media="screen,print" href="jquery.excel2canvas.css" /><script type="text/javascript" language="javascript" src="flotr2.js"></script><script type="text/javascript" language="javascript" src="jquery.excel2canvas.min.js"></script><script type="text/javascript" language="javascript" src="jquery.excel2chart.flotr2.min.js"></script>

<script>$(function() { var data = ${excel.raw()};// さっきの JSON データを埋め込む $("#canvasHolder").excelToCanvas(data).css("width", $("#canvas").width());});</script>

... <div id="canvasHolder"> <canvas id="canvas"></canvas></div>

Page 9: Excel2 canvas

現状どれだけのことができるのか?◦ 次ページ以降覚えてる範囲で実装内容を解説◦ 言うまでもないが作ってないものは描画されない

この先どうなっていくのか?◦ ぶっちゃけ未定◦ ていうか最初に作ってから半年以上眠らせてたし。。。◦ Heroku の Addon にする話が実現すれば状況は変わる

かな?

ライブラリの明日はどっちだ?

Page 10: Excel2 canvas

必要なものから作る◦ できることはわかっているが自分が使ってないので実装して

いないものは結構ある できそうなことはやる

◦ 需要があって実装が可能なものはできるだけやりたいと思わないこともない

Excel のすべての機能を網羅することを目標としない◦ 存在すら知らない機能が山ほどあるに違いない◦ オブジェクトなどいかんともしがたいものはあきらめが肝

心◦ ていうか多分想像できると思うけど本気でめんどくさい。。。

(--

開発方針

Page 11: Excel2 canvas

罫線のスタイルは POIで取得できている

スクリプト側で厳密に描画しているのは以下◦ 実線◦二重線◦破線

異なる長さのダッシュ線は単純な実線として描画◦ スクリプトの修正だけ

でできるわけだが。。。

罫線

Page 12: Excel2 canvas

背景色、パターンの色、パターンの種類、すべて POI で取得できている

しかし、スクリプト側では単純に背景色で塗りつぶしているだけでパターンは無視している

これもスクリプトの修正だけでできるけど、全部はやりたくない

塗りつぶし

Page 13: Excel2 canvas

横位置は左詰め、右詰め、中央揃えに対応◦均等割り付けは CSS で「 text-align:jusify」を指定しているが

あんまり綺麗に表示されない 縦位置は上詰め、下詰め、中央揃えに対応 リッチストリング ( 単一セル内で文字の色や大きさを変

える ) には未対応 セル全体のリンクには対応 折り返して全体を表示、縮小して全体を表示には未対応

◦原則セルからはみ出す文字列は非表示◦ ただし、左詰めで隣のセルが空いている場合はセルをはみ出し

て文字列を表示 セルの結合には対応

文字列

Page 14: Excel2 canvas

Windows OS上のブラウザではOSにフォントがあればそれが使用される MacはOSにあるフォントセットが全く違う上に font-familyの日本語が不可なのでなんらかの変換が必要◦ とりあえずフォント名に「明朝」とか「ゴシック」とかがある場合は「serif」や「san-serif」を追加している◦ フォントがない場合はデフォルトのフォントで表示される

iOSとAndroidでは明朝フォントがそもそもない?のかほぼ常にゴシックで表示される。

フォント

Page 15: Excel2 canvas

POI の書式設定解釈は日本語 ( 特に日付関連 ) がメタメタなので自力でなんとかした

多分ほとんどの書式は正確にでるはず◦ 少なくとも日本語書式は◦英語書式は多分大丈夫だけど他の言語?に関してはデグレードしているかもしれない

ただし先頭が「*」で始まる書式は OS の情報を使用しているのでサポートできない

書式設定

Page 16: Excel2 canvas

コメント Bootstrap の

tooltip で実装 このためだけに

Bootstrap をinclude するのはイマイチなので実装変えるかも

Bootstrap がない場合はコメントは無視され、描画されない

Page 17: Excel2 canvas

なんとBASE64にして JSONの中に突っ込んでいる ちなみに描画は

◦ <img src=“data:image/jpeg;base64,… “/> あまり大きな画像を貼り付けてはいけない 回転等には対応していない (CSS3ではできそうだけど。。。 )

画像

Page 18: Excel2 canvas

JavaScript のグラフライブラリとしては Flotr2 を使用し以下に対応◦ 円グラフ◦ 棒グラフ◦ 折れ線グラフ◦ レーダーチャート

細かいプロパティ設定等は考慮していない◦ ので、見た目は Excel 上で見た場合とは大分異なる

ちなみにグラフ情報は POI では取得できないので OOXML直読み。。。(--

単純なグラフでかつ Flotr2 が対応しているもの (例えばバブルグラフとか ) は今後サポートする可能性はあるが組み合わせグラフなどにはおそらく対応しない。

JavaScript ライブラリは別のものに差し替えることができる設計になっているが多分対応されることはない◦ 最近は良さげなグラフライブラリがたくさんありすぎて何を使うのが良いんだかよくわからない。。。

グラフ

Page 19: Excel2 canvas

テストはほぼ xlsx のみで xls はほとんど試していない◦ だいたいは正しく出力されると思うがグラフや画像は無視されるはず◦ Xls は POI のバグもあったような。。。

テーマを使用している場合の色が正しく取れない◦ これはやり方がわからず色々なサイトを見て試行錯誤したあげくあきらめた。

(--◦ ある程度近い色になる場合もあればまったく異なる色になることもあってよ

くわからない。。。 Excel はデフォルトフォントによってセル幅の計算方法が変わる

◦ これはセル幅を「デフォルトフォントで何文字分」という持ち方をしているため。 ( なんで??? )

◦ 「MS P ゴシック (日本語版 )」と「Arial( 多分英語版のデフォルト )」 には対応したけど、それ以外のデフォルトフォントではセル幅が狂うと思われる。

クリップアート、その他の実装予定はない

その他

Page 20: Excel2 canvas

面倒なだけで特に難しいことはしていない やろうと思えばできることはまだたくさんあるが。。。

◦ ただただめんどくさい◦マイナーな機能は使っている人が本当にいるのか謎( Excel職人は

いると思うけど)◦ ほとんど使われることのない機能のためにスクリプトが肥大化する

のは避けたい などの理由でもはや自分では優先順位がつけられない (-- 実際のところサポートしている機能は Excel 機能のごく一

部でしかないが世の中のほとんどの人はその一部の機能しか使っていないような気がする◦今のままでもかなり使えるはず◦後は必要に応じてかな。。。 (^^;;;

まとめ