generated at
感動するUIの作り方 3連発
こんばんは
daiizdaiizです
Notaでの開発
Scrapboxチーム 2年
Helpfeelチーム 2年
趣味での活動
SVGにまつわるネタを研究
GUI勉強会に参加


本日の3本
履歴を遡るスライダー
タッチデバイスでの文字選択
表作成ツール


履歴を遡るスライダー
Scrapboxには、ページの過去のバージョンを表示する機能がある
一定期間が経っている状態で編集されるとスナップショットが撮られる
行単位での編集差分を確認できる
履歴をパラパラ見ていくための操作パーツを作りたい


真っ先に思いつくUIの例
HTMLのinput type="range"select要素で実装できそう?
履歴が多くなったときに選びづらくなる
スナップショットの総数がひと目で分からない


課題
スナップショットが撮られた瞬間と、そのバージョンが継続していた期間の両方を示したい
素早く前後のバージョンを比較したい
本文に集中してほしいので細かい設定をいじったりするのは無し

こんな感じでどうだろう
等間隔な目盛りを表示する
1目盛りずつ移動するためのPrev/Nextボタンも置いてみる
目盛りの間隔の調整が難しい
スライダーを操作できるくらいの余裕が欲しい
等間隔にしてしまうと時間感覚が無くなってしまう
どういうことだろう?takker
等間隔ではなく、対数スケールで表示したほうがいいとか?
版の生存期間を表現したいということだと思うyosider
あーなるほど!生存期間は版によって異なりますねtakker
勝手に全部同じだと勘違いしてしまった
SmoothSnapの出番か?takker
版の生存期間を長さで表現するのはよさそうだ
たしかに、スクロールUIってツマミで1点を表現するけど、本来は期間を示す場合は長さに意味が出るはずですよねakix


さらに改良できる?
編集履歴は多くなるだろうからツマミで期間調整するのは難しそう
→ 複雑さが増すので思い切って機能を削る
history一つの差分がそこそこ大きいのも、これができた理由の一つかなtakker
/villagepump/履歴スライダーのように非常に細かい差分まで出してしまうと、今度は矢印クリックで履歴を追うのにうんざりしてしまう
一気にジャンプできるUIでないと操作できる
表示領域が狭いので細かい調整をするのには向いていない
一気に数年前のを見たいときは現状のUIだと無理そうbalar

完成形
Prev/Nextだけを操作できるボタンを置くことにした
両者を近くに配置することでどちらの方向にもめくりやすい
スライダー上の点は棘状にすることで摘めない雰囲気を醸し出している
どれだけ間隔が狭くなっても、1pxの棘ならば密集しても重なることなく整列できる


タッチデバイスでの文字選択
Scrapboxのエディタはかなり特殊な実装
箇条書きリンクの書き心地を追求するために独自に作り込まれている
これにあわせて文字選択操作も自前で作っている
ブラウザ標準APIのwindow.getSelectionは使えない
>カーソルの縦棒はdiv
表示倍率を縮小したときに消えてしまうことがあったので、いまはSVGのrectになってる
>緑の範囲選択もdiv3つ

課題
マウスがない環境ではどうやって操作すればいいだろうか
狭い画面でいかに狙い通り選択してもらうか
縦と横のスクロールで微調整していくのが難しいのだけど、なんとかなるものか?


まずは身近な例を観察
iOS
範囲を拡縮するツマミの位置が、選択領域の始点では上側、終点では下側
Android
ツマミはともに下側
OSでのつまみの位置の違いに着目したことがなかったので面白いですteyoda7takker
iOSだとそうなるんだ!takker


思いつく限りいろいろ試す
想像やモックに頼らずに実際のコンテンツで動かしてみるのがよい
文字、画像、リンクが多いなど、どんなページでも操作しやすいか?
旅行先での移動中にさくっと書けるか?

画像を選択中に記法表示モードに切り替えないほうがスムーズでいい、とか気付ける
画面が広いPC版では問題なかったが、スマホではガタつきが気になる
PC
スマホ


ツマミの設計に苦戦
触れる領域が狭すぎるのが問題
複数行選択されたときの見せ方が難しい問題
いろんな形状を検討したけれどどれも納得がいかなかった


そもそもツマミは必要か?
小さい画面で小さいツマミを出すと誤タップを誘発しやすい問題
システムUIではなく、HTMLの一要素として表現するしかないので他の要素と衝突しがち
かなしいyosidertakker
選択範囲の両端を直接触ってもらえばよい!
ツマミの色を分ける必要もないのでは?
緑色に同化した結果、見事にツマミが無くなった
不要なものを出さないことでシンプルになった
ツマミが飛んで来てくれるのとても使いやすくて助かっています。mgn901
初めて触ったときOSレベルでもそうなってほしいと思いました
ツマミを付けなかったのはツマミでうまくいかなかったからかtakker
正直ツマミのほうがいいんじゃないかと思っていた
必ずしもツマミにこだわらなくてもいいのではないか?
ツマミをなくすとしたら?
というように問いの切り口を変えてみた、という事例でした daiiz
今後「やはりツマミが必要なのでは?」という問いが戻ってくる可能性もありますね
文字選択がかなり難しい
両端をつかむと、指でどこをつかんでいるのかわからなくなる
選択解除と誤認識してしまうことがある
1文字単位の微調整で多いかも
Firefox for Androidだとほとんど動かなかった覚えがある
1年前のことだから、今改善したかはわからない

「微調整が難しい」に立ち向かう
無意識に次の操作を連続して行っている
① 長押しで初期範囲をつくる
② 目的の行までざっくりと縦スクロールする(画面外までスクロールするときもある)
③ 行内の目的の文字まで横スクロールする
② は不要なのではないか?
選択範囲は連続しているのだから、範囲の両端が決まればそれで十分なはず
指で隠れていて正確な位置を把握しづらい問題も解消される

最終的にこうなった
目的の両端付近の文字をちょっとなぞるだけでよい
初期範囲との位置関係から始点 or 終点を特定できる
終点が画面外にあるときは普通にスクロールすればいい
不要な操作を求めないことで、無意識のうちにこなされるタスクが減った!



仕上げ
たしかに便利なんだけど、初見でユーザーに理解してもらえるか?
→ よく知られている一般的な操作方法もサポートする
長押しは理解出来なさそうtakkerMijinko_SD
このまえ部活で使ったときに、スマホからどう文字を入力したらいいかわからないという話が出た
すぐカーソルがでて入力されるようになってもいいのかも
でもswipe cursorとの兼ね合いもあるか
ですね、長押しで編集開始するのは難しい。改善していきたいですね daiiz




表作成ツール
Helpfeelの記事で少しリッチな表を使いたいので開発中
既存のライブラリを試したが、あと一歩改良したい気持ちがあった
既存ライブラリでいいかんじのやつあんまりないtakker
React Tableとか個人で試したことがありますが挫折しました
完全にイチから設計する、という挑戦
ほぼプロジェクトXakix
つよいteyoda7takkermeganiitetsuya-k
Scrapboxでキレイな表を作りたいときがあるので欲しい!!!!meganii

目標
こういう表を簡単に作れるようになる


課題
極限まで直感的に操作したい
特にセルの結合と分割が難しい
+1akixakixakix
狭いセルでストレスなく編集するには?
マウスや矢印キーでのセルの選択など
こういうメニューは避けたい
「この行を削除」「C列を削除」「3行目を削除」
「この下に1行追加」
「横方向に3マス結合」
あるあるwakix
セルに対する操作ボタンが並んだツールバーもやめたい
どうする?


各セルに操作用のハンドルを付ける
セルの右と下だけにdiv要素を配置する
これから紹介する操作がこれで綺麗に収まる
最初は4辺のすべてに必要だと思い込んでいた
上と下、左と右の当たり判定が厳しくて困る
色々考え込んだ後の休憩中に2辺だけでいけると確信した
喫茶店のお手拭き?
ナプキン!! 増井俊之
サルバドール・ダリみたい
こういう即興のメモ見るの好きteyoda7meganiik
心の余裕も大事


行や列の追加、削除
まずは最も基本的な操作から
目的のセルの仕切りの位置にカーソルを持っていくだけでいい
その位置でできる操作だけがサジェストされる
必要なときだけ見せる
ボタンを作用点の近くに出すことで「いま何ができるのか」が明瞭になる
すごく高速で機能にアクセスできるMijinko_SD


セルの結合、分割
一番難しく、もっともこだわりたかった部分
対象のセルをチェックボックスで選んだ後にボタン操作する?
モードの切替も発生する
編集と選択のモードが必要になる
「見た目が悪い」だけでなく、一気に難しいツールになってしまう
ありそうな上にヤバいUIで良いakix
ホラーUIじゃんtakker
目的の仕切りの位置にカーソルを持っていくだけでいい
結合: 仕切りを取り払いたい場所
分割: 仕切りを作りたい場所
ボタン操作によって影響を及ぼす範囲が事前に示されるので戸惑わない
名付けるならpreview UI?takker
CLIでいうdry runみたいな
どんな順番で結合や解除をしても思い通りの形状を作れる
順不同で同じ結果が得られる
セルを直接触れている感覚が得られてとても良い

Excelを倒せるのでは?!meganiimgn901
なんで今までこうなっていなかったんだろうっていうレベルの自然さを感じてすごい!yutaro
むちゃくちゃ既視感があるtakker
どこかのなにかで見たことあるような……
いずれにせよどうなるかがすぐわかるUIは好きです
incremental searchとも共通するかも
すぐに結果が出てくる
リンク入力補完も、次どうなるかがわかってから補完する

Tips: 結合されたセルの形状情報はどうやって持っておくのがいい?
<td colspan="列の結合数" rowspan="行の結合数"></td> に倣うのが結局一番扱いやすかった。HTMLはよくできてる daiiz
結合範囲の左上のセルで両方向の結合量を持っておく
他のセルでも便宜上の値を持っておく
結合されて独立していないセルでは結合量を0にする
結合の座標情報は左上のセルだけが持っていればいい
他のセルは自身が上または左の辺を構成しているかを0/1で持っておく
例: 括弧内の値は (colspan, rowspan) を表す
列のみ結合
行のみ結合
両方向で結合


テキスト編集とセルの横幅調整
選択したセルのそばにエディタが現れる
テキストを書いていると横幅を調整したくなる
編集中にセルの仕切りをドラッグできるといい
横方向だけの移動だが手は縦方向にもブレるものなので、画面全体で移動量を補足できるようにしておく
カーソルがエディタ内部に侵入してしまってもキャンセルされないように
大胆に操作できるような配慮をしておく

セルの高さの調整は?
シンプルさを保つため敢えて実装せず、内部のコンテンツの高さに任せることにした
機能を削る

調整中は縦の青い補助線は出ない?
出さないことにした
セル内に画像が含まれている場合など、高さが激しく変化して再計算するのが大変なので諦める


矢印キーでのセルの移動
結合されているセルを跨いだときの挙動に気を遣う必要がある
同じ列や行内で一貫した選択操作ができているかが大事
例: 「Scrapbox」のセルがある3列目での下移動
横方向に結合されたセル(5行目)を通過した直後に、3列目の「Node.js」が選択される
実装時にサボると通過後に2列目 (横方向の結合された一番左のセルの位置) に移動してしまう
可逆性を保つ
例: 「Helpfeel」のセルから下移動を開始して跳ね返った後に、元の位置に戻ってこれる


Undo / Redo
Ctrl + Z, Ctrl + Shift + Z で何度でもやり直しができる
一番簡単な実装はスナップショット方式
各操作後のテーブル全体の結果をすべて蓄積しておき、逆順に適用するだけで実現できる
+1akixakixakix
セル結合(2回)→ Ctrl+Z(2回)→ Ctrl+Shift+Z(2回)


実質Undo
セルの結合・分割の連続操作はよく観察するとUndo的な挙動をしている
= 分割は結合の逆操作とも捉えられる
同じ作用点で結合と分割が連続して行われたときのみ発動する
結合されたテキストの再分割の結果が直感的になる

普通に分割すると
結合されていたセル内のテキストや画像は分割後のどちらのセルに属するべきか?
一番シンプルな解決法はどちらかに寄せてしまうこと
これでも分割操作としては間違いではないが違和感がある

Undoの一種として扱って分割すると
結合前に所属していたセルに再分割することが可能になる
直前までの内容が復元されるので気の利いた賢い動きになる
富豪的プログラミングの恩恵?mgn901

Tips: 「実質Undo」の実現方法
分割前後のテキスト履歴を各セルで個別に保持することなく、Undoを応用して実現できる
操作履歴 Unmerge前
Op Data ------------------- Init data0 MergeCol data1 <-- 最新
操作履歴から復元先(Init)を適用する
この際にUnmergeとその逆操作の履歴を作って挿入しておくと、さらにUndo/Redoされても辻褄が合う
操作履歴 Unmerge後
Op Data ------------------- UnmergeCol data0 MergeCol data1 Init data0 <-- 最新


おまけ: 生成物の出力形式
このようなSVG画像
svg
<svg> <foreignObject> <html> <style>...</style> <table>...</table> </html> </foreignObject> </svg>
foreignObjectタグには任意のHTMLを書ける
画像を埋め込む場合はbase64エンコードしておくとよい
嬉しさポイント
HTMLのtableタグとして保持しておけるので他のツールでも使いまわしやすい
SVG画像なのでimgタグでも表示できる
Scrapbox上でプレビューできる!


まとめ
感動するUIを作るには
UIパーツや各操作の本質を考える
身近な例も観察する
オリジナルな快適さを探究するものの、一般的な使い勝手と乖離しすぎないよう気をつける
この塩梅が難しいけれど、頑張ってこだわりを届けていこう
+1akixakixakixakixakixakix
応援takkermeganiimgn901yutaromeganii
触りながら調整を繰り返していくしかない
複雑さを回避するために実装しないという決断を下す勇気を持つ

すごいなー 増井俊之
論文になるレベル... 増井俊之
Scrapbox上でどう展開するんだろう
期待meganii
Scrapboxにもこの表ほしいyosider
ぱっと思いつくとこだとコードブロックにデータ展開?takker
hyperscorebox見る限りだと実装はそんなに問題じゃなさそう
快適さを追求するにはもっと練らないとだけど