リング状プログレスUI
今回は⇧これを Web Component で作って、その応用例としてのポインター長押し判定も雑に書いてみたところ、とりあえず期待通りに動作するものはできたのでそのメモ。
CodePen
See the Pen progress-ring web-component usagi ver. by Usagi Ito (@usagi-network) on CodePen.
作り方
ProgressRing
(=<progress-ring>
)
-
class ProgressRing extends HTMLElement
で Web Component のクラスを定義 - うまいこと
innerHTML
に<svg>
でそれっぽいUIを作る - そのままだと
createElement
やsetAttribute
に対応できないので、HTMLで静的にタグを定義するほかに ES で動的に作って弄れるように -
static get observedAttributes()
と -
attributeChangedCallback(name, _old_value, new_value)
を定義 -
<svg>
の<circle>
のr
属性は read-only なのでこれの更新が必用になる場合(stroke
やradius
が変更された場合)はルート要素内部のinnerHTML
をごっそりthis.regenerate()
しちゃう仕組みに調整 -
opacity
transform
transition
で簡単な演出を仕込む
ProgressRing
を応用した「ポインター長押し判定」
-
pointerdown(e)
&begin_ring({...})
で判定時間や完了時/キャンセル時のファンクターなどパラメーターを受け取りつつ、 -
let pr = <progress-ring>
を生成 -
let begin = new Date().getTime()
で開始時刻を保持 -
requestAnimationFrame
でpr
にbegin
からの経過時間と判定時間から完了までの進捗をsetProgress
- キャンセル処理用に
pr
にlet cancelation = false
ステートをキャプチャーした.cancel()
を追加してreturn
、呼び出し元側で.cancel()
をトリガー可能に
1. 同様にbegin_ring
側で移動距離によるキャンセル判定用に初期のx
y
をpr.initial_position
に追加で保持させています -
pointerup(e)
で、 .cancel()
-
pointermove(e)
で -
pr.initial_position
e.x
,e.y
から移動距離が一定以上か判定して .cancel()
おまけ
できた表示を見ていたらアニメの演出とかでありがちな「たくさんロックオン!」みたいな絵もこれで再現できちゃいそうなので遊んでみました。中ボタン押しで⇩こうなります。
参考
-
https://css-tricks.com/building-progress-ring-quickly/
-
<ring-progress>
の基本的な実装はこの記事を原型にしています。🙏
-