JavaScript
RxJS
RxJS6

rxjs6 でクリックとドラッグを識別する


TL;DR

サンプルコード があるのでそれでだいたい分かると思う。


はじめに

同じ DOM に対して クリック処理とドラッグ処理をさせたいときってありますよね?

rxjs6 ならそこそこ楽に書けますよ。


実装

まずこちらの html と css を用意して

<div id="sample" />

#sample {

position: absolute;
top: 100px;
left: 100px;
width: 100px;
height: 100px;
background-color: #00a1e9;
}

#sample に対するクリックとドラッグの識別をやってみます。

具体的には ドラッグ開始クリック を識別します。それぞれ以下と定義します。

1. ドラッグ開始 … マウスが押されてから一定時間押しっぱなしであること

2. クリック … マウスが押されてから一定時間にマウスが離されること

上記処理の 早く発火した方 を拾うことができればいいわけです。

まず source のストリームを作ります。

1. 2. をそれぞれ of(e).pipe(delay(200))fromEvent(el, 'mouseup') と実装しています。

これらのストリームを merge して first で早く発火したほうを次へ流します。

最後に share で以降のドラッグとクリックの subscribe で同一のストリームを受け取るようにします。

const el = document.getElementById('sample')

const source = fromEvent(el, 'mousedown').pipe(
switchMap((e) =>{
// 200ms 遅延した mousedown イベント または
// mouseup イベントの
// どちらか早く発火した方を次へ流す
return merge(
of(e).pipe(delay(200)),
fromEvent(el, 'mouseup')
).pipe(first())
}),
share()
)

続いて subscribe の実装ですが、e.type === 'mouseup' でクリックかドラッグ開始か判別しています。

あとは煮るなり焼くなりしてみてください。

// e.type でクリックかドラッグか識別する

const click = source.pipe(
filter((e) => e.type === 'mouseup')
).subscribe((e) => {
alert('click!')
})

const drag = source.pipe(
filter((e) => e.type !== 'mouseup')
).subscribe((e) => {
alert('drag!')
})


まとめ

楽ですね。