// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.collide.client.util.dom;
import elemental.events.MouseEvent;
import elemental.util.Timer;
/**
* A helper that detects mouse movement pause.
* <p>
* When mouse movement pause is detected, {@link Callback#onMouseMovePaused()}
* is invoked once. Even if mouse stays still for a long time,
* {@link Callback#onMouseMovePaused()} is only invoked once. Only after mouse
* starts to move again, the detector resumes.
*/
public final class MouseMovePauseDetector {
/**
* An interface that receives callback from the {@link MouseMovePauseDetector}
* when mouse move pause occur.
*/
public interface Callback {
void onMouseMovePaused();
}
private final Callback callback;
private final Timer getRevisionWhenDragTimer;
/**
* If mouse did not move after DEFAULT_PAUSE_DURATION_MS, we consider move
* paused.
*/
private static final int DEFAULT_PAUSE_DURATION_MS = 500;
private static final int MOUSE_INVALID_POSITION = Integer.MIN_VALUE;
private static final int MOUSE_MOVEMENT_THRESHOLD_SQUARED = 900;
// (lastMouseX, lastMouseY) is the last mouse location.
// It gets reset if mouse movement is over the threshold.
private int lastMouseX = MOUSE_INVALID_POSITION;
private int lastMouseY = MOUSE_INVALID_POSITION;
private boolean enabled;
public MouseMovePauseDetector(Callback callback) {
this.callback = callback;
getRevisionWhenDragTimer = new Timer() {
@Override
public void run() {
mousePaused();
}
};
}
public void start() {
enabled = true;
lastMouseX = lastMouseY = MOUSE_INVALID_POSITION;
}
public void stop() {
enabled = false;
getRevisionWhenDragTimer.cancel();
}
public void handleMouseMove(MouseEvent event) {
if (!enabled) {
return;
}
if (lastMouseX == MOUSE_INVALID_POSITION
|| isMoved(event.getClientX(), event.getClientY(), lastMouseX, lastMouseY)) {
// Cancel current timer and start timeout.
// Whenever the timer timeouts, mouse has paused long enough.
getRevisionWhenDragTimer.cancel();
getRevisionWhenDragTimer.schedule(DEFAULT_PAUSE_DURATION_MS);
lastMouseX = event.getClientX();
lastMouseY = event.getClientY();
}
}
private void mousePaused() {
if (!enabled) {
return;
}
callback.onMouseMovePaused();
}
private boolean isMoved(int x1, int y1, int x2, int y2) {
int deltaX = x1 - x2;
int deltaY = y1 - y2;
return deltaX * deltaX + deltaY * deltaY > MOUSE_MOVEMENT_THRESHOLD_SQUARED;
}
}