No Regrets in Bathing

カレーを週に一度食っていく

Excelシートを憎み、愛した男

Excelシートが憎い。

Excelシートでの書類作業の辛さは言わずもがな。

  • データベースもどき
  • アプリもどき
  • 帳票出力
  • Excelシート上でのコーディング
  • エビデンス作成
  • UMLなど

以上のものについて、すべてExcelでの作成経験がある。あの世にもExcelシートを作らされる地獄がきっと存在するだろう。

Excelシートが憎い。Excelの万能性ゆえ、落とし込まなくていいものまで落とし込まれ、地獄を生み出す。みんなExcelなら慣れてるので、その他の選択肢は選ばれない。何度かMarkdownからExcelにコンバートするようなツールを書いたけれど、書式が変われば捨てざるを得ない。結局今もExcelを書き続けている。辛い。

でも待って欲しい。あれほど一括編集をエレガントにこなせるUIが他にあるだろうか(2大エディタに習熟した場合を除く)。図も書ける。式は素人でも使えるが、プログラミングの一形態ですらある。Excelやっぱり凄いよ。こんな凄いものが存在するなんて信じられない。気がつくとExcelのことばかり考えている。Excelのことが本当は好きなのかも知れない。

だから、SVGExcelスプレッドシートを自作した。車輪の再発明だ。

f:id:hashrock:20180312013009g:plain

DEMOはこちらから

ロゴも作った。

https://user-images.githubusercontent.com/3132889/37255669-e971baf2-2592-11e8-823c-0dcadcb3b772.gif

リポジトリはこちら。

github.com

すでにhandsontableという、実用的なスプレッドシートコンポーネントが存在するため、 フルスクラッチで小さく書くのを目標にしている。

下記の通り、コンポーネントは1ファイルの.vueだけで書かれており、Vue以外への依存はない(…と思ったけど、考えたらrebootに依存してた。そのうちどうにかします)。今の所413行。

vue-spreadsheet-lite/SushiGrid.vue at master · anydown/vue-spreadsheet-lite · GitHub

結構頑張って作ったけど、機能不足やバグが多数あったり、そもそもまだコンポーネント単体としてnpmから使えないとか、いろいろな不備がある。まだ実用は出来ないので、ご容赦願いたい。

SVGとVueで難しいコンポーネントを作ろう

SVGとVue.jsの組み合わせが最高なのは下記の記事でも書いたとおり。身の回りでも多くの人がVue.js + SVG遊びに興じているのを観測している。

hashrock.hatenablog.com

もっと多くの人にVueとSVGを使って欲しいので、今回は複雑なものを作る時のTipsも足しておく。

スプレッドシートを作る手順

最初はまずSVGを手書きし、プロトタイピングするのをおすすめする。

ちょっと思い出しながら書いてるけど、初期のコミットは下記のようなコードだった。

<template>
  <svg width=500>
    <rect x=0 y=0 width=100 height=24>
    <text x=0 y=12 width=100 height=24>hoge</text>
    <rect x=100 y=0 width=100 height=24>
    <text x=100 y=12 width=100 height=24>fuga</text>
  </svg>
</template>
<style>
rect{
  fill: white;
  stroke: #999;
}
</style>
  • vue createで作成されるHello.vueファイルを編集しながら作り始める。
  • この時点でロジックはまったくない。SVGのrectやtextで作りたいものが出来るのかをまず検証する。
  • ある程度要素同士にまとまりが見えてきたら、g要素でグルーピングし、transform="translate(x, y)"の形に書き直す。

それから、Vueのdataに配列を入れて、v-forで要素を生成する。

コツは、やはり見た目から先に作り込むこと。特にSVGにはz-indexが無いため、書いた順に重ね合わせされるなどの罠が存在する。 自分はDIVなどのHTML要素でコンポーネントを作るときも、まずHTMLタグでモックアップを作ってから、後でロジックを差し込む作り方をするほうが多い。

その場編集(In-place editing)

要素をクリックして、その場で文字列を書き換えられるような仕組みをIn-place editingと呼ぶ。

In-place editingは知る限り下記の3つの方法がある。

  • contenteditable属性を使う
  • クリック後、要素の上にテキストフィールドを乗せる
  • 見えないテキストフィールド(opacity=0)を最初からコンポーネント上に置いておき、クリック位置に移動する

今回のスプレッドシートは、任意のタイミングでのキー入力もテキスト入力として扱わないといけないので、3番目の見えないテキストフィールドを採用した。2番目は付箋を作ったときに採用した。

In-place editingを作るときには、特にIMEの取扱に注意が必要で、ラテン語圏のOSSIMEを上手く扱えていないケースが多い。そもそも入力出来なかったり、変換確定のEnterキーで入力が終了してしまったり。 最近は同じくIMEを必要とする中国語圏のユーザがOSSに関わることが多くなったからか、状況は改善している。

選択範囲など

SVGはz-indexによる重なり順の制御が出来ないと書いたが、下記のように分類すれば大抵のケースでうまくいく。

f:id:hashrock:20180312022916p:plain

UIレイヤーは、選択範囲やボタン、ダイアログなどに当たる。ベジェハンドルやバウンディングボックスなどもここ。

コンテンツレイヤーは、編集対象のコンテンツに当たる。今回の場合であればセルの内容。

これら2つのレイヤーを重ね合わせることで、多くの問題が解決できる。具体的にはそれぞれをSVG要素でくくり、position: absoluteで同じ位置に配置してしまう。

UIとコンテンツを同じSFCの中にまとめてしまいがちだが、そうなると表示順の罠を踏むことになってしまう。 UIのような、クリッカブルな要素がコンテンツの下に来ることは、通常ありえないので、コンテンツと完全に分けてしまうという考え方になる。

今後の予定について

Biliでバンドルを作って、npmに公開したいと思っている。機能不足を解決したタイミングで頑張りたい。

github.com

あと、ちょっと作りかけているけど、markdown tableをスプレッドシート / テキストエリアで双方向に編集できるものも作りたい。下記はスペース区切りのもの。

f:id:hashrock:20180312030806g:plain

テキストからヘッダを生成する場合は、ヘッダの幅を自動算出しなくてはならない。ちょっと考えないといけない。

おわりに

Excelを追いかければ追いかけるほど、Excel作った奴らまじで凄いという感想しか出ない。今回作ったものをExcelにするには、複数の選択領域をサポートしたり、セル内の改行や結合セル、罫線、図、数式など、とんでもないカロリーの機能を実装しなくてはならない。

だからこそ、Excelは代替されにくいのだろう。互換ツールを作ることも難しいし、そのメリットも少ない。出来の良いツールが市場に居座ることで、そのツールに依存したエコシステムが形成され、誰も逃げられなくなってしまう。

あと、ツールに対して恨みごとを言いたくなってしまうときは、やはり車輪の再発明をしてみるべきなんだと思う。今回で自分はExcelを作った人に対する敬意が少し増したような気がする。作ってみなきゃ人の苦労は分からない。

まぁ、スプレッドシートの仕事が来たら、こんなんじゃなくて普通にhandsontable使おう。ちょっとでかいけどほんと良く出来てます。