Vyacheslav Zhabitsky
Vyacheslav Zhabitsky

Reputation: 353

Need to filter mousemove event only when low speed of mouse moving

in case when user very fast dragging via observable mousemove event, we don't need to emit each px this events, only when he trying to aim before drop element (we can catch this moment bcs speed of mouse will be low), is there any trick for this?

mb some case to get speed via px/per seconds then filter or etc...

Upvotes: 0

Views: 329

Answers (1)

kos
kos

Reputation: 5364

You could do a pairwise comparison of the mouse position, measuring the distance between events and filtering out high velocity moves:

const { fromEvent } = rxjs;
const { pairwise, map, filter } = rxjs.operators;

const block = document.getElementById('block');
const mousemove$ = fromEvent(block, 'mousemove');

mousemove$.pipe(
  // filter out high velocity movements
  pairwise(),
  map(([a, b]) => ({
    d: getDistance(a,b),
    x: b.x,
    y: b.y
  })),
  filter(e => e.d < 10)
).subscribe(e => {
  console.log(e.x, e.y);
});

function getDistance(a, b){
  return Math.sqrt(
    Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2)
  );
}
<script src="https://unpkg.com/[email protected]/bundles/rxjs.umd.min.js"></script>
<style>
  #block {
    margin: 3rem;
    padding: 6rem;
    background: rebeccapurple;
  }
</style>

<div id="block"></div>

This depends on the rate of browser emitting and handling those events.

So you'll probably will need to add timeInterval to calculate the speed, not just the delta.

--

OR you could achieve this by using debounceTime, throttleTime, auditTime or sampleTime.

debounceTime vs throttleTime vs auditTime vs sampleTime

Heres an example using sampleTime 300ms, that I would recommend:

const { fromEvent } = rxjs;
const { sampleTime } = rxjs.operators;

const block = document.getElementById('block');
const mousemove$ = fromEvent(block, 'mousemove');

mousemove$.pipe(
  // sample only once per 300ms
  sampleTime(300)
).subscribe(e => {
  console.log(e.x, e.y);
});
<script src="https://unpkg.com/[email protected]/bundles/rxjs.umd.min.js"></script>
<style>
  #block {
    margin: 3rem;
    padding: 6rem;
    background: rebeccapurple;
  }
</style>

<div id="block"></div>

Surely, you could also combine "delta move" measuring with "sampling"

Hope this helps

Upvotes: 2

Related Questions