Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
ぬるぬる動くSwipeCard UIをClojureScriptで実装してみた
Search
BOXP
May 30, 2019
Programming
0
66
ぬるぬる動くSwipeCard UIをClojureScriptで実装してみた
BOXP
May 30, 2019
Tweet
Share
More Decks by BOXP
See All by BOXP
Cluster Creator Kitに入門してみた
boxp
0
66
LookingGlassPortraitあそんでみた
boxp
0
38
肉体を捨てた話
boxp
0
64
A story about releasing a online pairing service for avatars living in virtual worlds
boxp
1
290
VketのブースにVRoid製うちのこを召喚してみた
boxp
0
180
Hito Hub 2.0
boxp
0
1.1k
バーチャルマーケット3に ポスターを貼ってみた件
boxp
0
1.4k
趣味でGOOGLE KUBERNETES ENGINEを試したら 財布が薄くなったはなし
boxp
0
1.3k
趣味でつくる アバター×アバター マッチングアプリをリリースした話
boxp
0
110
Other Decks in Programming
See All in Programming
創造的活動から切り拓く新たなキャリア 好きから始めてみる夜勤オペレーターからSREへの転身
yjszk
1
130
Webエンジニア主体のモバイルチームの 生産性を高く保つためにやったこと
igreenwood
0
330
Jakarta EE meets AI
ivargrimstad
0
240
CSC305 Lecture 26
javiergs
PRO
0
140
선언형 UI에서의 상태관리
l2hyunwoo
0
160
Semantic Kernelのネイティブプラグインで知識拡張をしてみる
tomokusaba
0
180
Keeping it Ruby: Why Your Product Needs a Ruby SDK - RubyWorld 2024
envek
0
190
Cloudflare MCP ServerでClaude Desktop からWeb APIを構築
kutakutat
1
550
暇に任せてProxmoxコンソール 作ってみました
karugamo
2
720
Go の GC の不得意な部分を克服したい
taiyow
3
780
PSR-15 はあなたのための ものではない? - phpcon2024
myamagishi
0
110
テスト自動化失敗から再挑戦しチームにオーナーシップを委譲した話/STAC2024 macho
ma_cho29
1
1.3k
Featured
See All Featured
Faster Mobile Websites
deanohume
305
30k
Building a Scalable Design System with Sketch
lauravandoore
460
33k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
17
2.3k
Writing Fast Ruby
sferik
628
61k
[RailsConf 2023] Rails as a piece of cake
palkan
53
5k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
656
59k
Git: the NoSQL Database
bkeepers
PRO
427
64k
Typedesign – Prime Four
hannesfritz
40
2.4k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
169
50k
GraphQLの誤解/rethinking-graphql
sonatard
67
10k
Designing on Purpose - Digital PM Summit 2013
jponch
116
7k
Agile that works and the tools we love
rasmusluckow
328
21k
Transcript
BOXP ぬるぬる動くSwipeCard UIを ClojureScriptで実装してみた
None
こんな風にぬるぬる動く SwipeCardのつくりかた をまとめます
もくじ Rendering Performance チューニングの基本 SwipeCardにおける Rendering Performance チューニング ClojureScriptによる SwipeCardの実装
Rendering Performance チューニングの 基本
引用元: RAIL モデルでパフォーマンスを計測する https://developers.google.com/web/fundamentals/performance/rail
全部0~16msで 動かないと だめ?
No!
ライフサイクルに 応じて 必要なパフォーマンスを 満たす
Webアプリ 4つのライフ サイクル (RAILモデル) • Response: ユーザーの入力に対する応答中の状態 • Animation: アニメーションの再生やSwipeCardをドラッグしている状態
• Idle: ユーザーの入力を待機している状態 • Load: コンテンツ読み込み中の状態 引用元: RAIL モデルでパフォーマンスを計測する https://developers.google.com/web/fundamentals/performance/rail
各ライフ サイクルに 求められる Performance •これよりも遅いとユーザーは操作と反応のズレを感じる 100ミリ秒以内の応答 •1000ms / 60fps -
ブラウザによるレンダリング時間 = 10ms Animation中は10ミリ秒以内に画面をレンダリングさせる •100ミリ秒以上かかる処理はアイドル時間まで後回し •ユーザー入力へのレスポンスが最優先 アイドル時間を利用したタスク分担 •1000ミリ秒より長いとユーザーの集中力が切れる •このスライドでは触れません 読み込みは1000ミリ秒以内に
まとめ どの程度の パフォーマンスが必要か ライフサイクル毎に分けて考慮する RAILモデル ユーザーの入力には100ミリ秒以内に応答する アニメーション実行中は10ミリ秒以内にレンダリング処理を完了さ せる 時間のかかる処理はアイドル時まで後回し
SwipeCardにおける Rendering Performance チューニング
SwipeCardにおけるライフサイクル 待機中 ドラッグ開始 ドラッグ スワイプ もとの位置に 戻る マッチング オーバーレイ 表示
次のカードを 最前列に Idle Response Animation
SwipeCardにおけるライフサイクル 待機中 ドラッグ開始 ドラッグ スワイプ もとの位置に 戻る マッチング オーバーレイ 表示
次のカードを 最前列に 最重要 Idle Response Animation
カードをドラッグする時 •RAILモデルに当てはめるならAnimation •目標は1frameあたり10msで処理を終えること ユーザーのドラッグ操作に合わせてカードを動かす •CSSのアニメーションだけではほぼ実現不可能 ユーザーの入力に対して変化するアニメーション
1frame/10ms 実現のために 不要な処理を削る
Webページが描 画されるまで • 5つの処理を行うパイプラインとして表現される • Paint処理が一般的に重くなりがち • Layout処理がトリガーされると必ずPaint処理もトリガーされる 引用元: ペイントの複雑さの簡略化とペイントエリアの縮小
https://developers.google.com/web/fundamentals/performance/rendering/simplify-paint-complexity-and-reduce-paint-areas
パイプライン中の 不要な処理を飛ばす Paint・Layout処理を実行させない • Paint処理はまず10msでは終わらない • JavaScript,Style処理もスワイプ処理では削る Composite処理のみで描画できる スタイルを利用する •
transformとopacityのみ 他の要素を再計算させない • Animationさせる要素を別レイヤーへ分ける • will-change: transform; によって別レイヤーが作成可能 Paintが行われていないかChromeDevToolでチェック
その他の最適化 • 不要なLayout処理(強制同期レイアウト)の回避 • スタイルの読み出しと書き込みを1frame内で行うことで発生 する • Reactを利用している場合、スタイルの書き込みは非同期に 行われるため問題にならない •
メインスレッドからUI描画以外の処理を徹底的に排除する • API呼び出しをWebWorkerから行ったり、バッチ化しておい てIdle時に実行させるなど
まとめ • RAILモデルのうち、Animationへの最適化が鍵 になる • 違和感なくアニメーションさせるためには、Paint 処理を避けた実装が必要不可欠 • transform・opacityスタイルを使った実装 •
アニメーションさせる要素を別レイヤーに配置し て余計なLayout処理を避ける • will-change: transform;
ClojureScriptによる SwipeCardの実装
SwipeCardの基本的な仕組み • 二枚の重なり合った要素を使って表現 • 待機状態・Skip・お気に入り登録・初期位置への移動中の 4つのフェーズ • ReagentのLocalStateで状態管理
SwipeCardの LocalState カードの内容 4つのフェーズ タッチポイント座標
ドラッグ そのまま離す お気に入り スキップ 次のカードを表示
ドラッグ そのまま離す お気に入り スキップ 次のカードを表示
SwipeCardのドラッグ処理の実装 • touchmoveイベントハンドラからLocalStateにタッチ ポイントの座標を保持 • 保持された座標からtransformの値を返す関数を 使ってスタイル指定 • Paint処理を避けるためtransformのみで実現
ドラッグ そのまま離す お気に入り スキップ 次のカードを表示
カードを 元の位置へ 戻す実装 • touchendイベント発生時点でのタッチポイントから、元の位置の座標へ のアニメーションを一番上のカードへ差し込む • これでアニメーション中はComposite処理のみで完結できる
ドラッグ そのまま離す お気に入り スキップ 次のカードを表示
スキップ/ お気に入り 処理の実装 • アニメーションは元の位置へ 戻す処理と同様の方法で 実現 • 移動先を元の位置では なく画面外にするだけ
• 戻す時と同様に Paint処理を省略できる
追加のカー ド取得実装 • 表示させるカードが枯渇してきたら、お気に入り/スキップ 処理実行後にWebWorkerを使って追加取得する • 状況によってはアニメーションと取得処理が重なり、fpsが 低下する可能性があるためWebWorkerに処理を追い出す
API Server WebWorker re-frame Reagent Component dispatch subscribe effect request
response dispatch
まとめ • SwipeCardの状態はre-frameではなくReagentの LocalStateで管理している • アニメーションはstyleへkeyframeを直接埋め込 んで実現している • ページング取得はWebWorkerから行った
続きはGitHubへ https://github.com/boxp/vr-match
Thanks!