104 lines
2.8 KiB
JavaScript
104 lines
2.8 KiB
JavaScript
export default class HoverIntent {
|
|
|
|
constructor({
|
|
sensitivity = 0.1, // speed less than 0.1px/ms means "hovering over an element"
|
|
interval = 100, // measure mouse speed once per 100ms
|
|
elem,
|
|
over,
|
|
out
|
|
}) {
|
|
this.sensitivity = sensitivity;
|
|
this.interval = interval;
|
|
this.elem = elem;
|
|
this.over = over;
|
|
this.out = out;
|
|
|
|
// make sure "this" is the object in event handlers.
|
|
this.onMouseMove = this.onMouseMove.bind(this);
|
|
this.onMouseOver = this.onMouseOver.bind(this);
|
|
this.onMouseOut = this.onMouseOut.bind(this);
|
|
|
|
// and in time-measuring function (called from setInterval)
|
|
this.trackSpeed = this.trackSpeed.bind(this);
|
|
|
|
elem.addEventListener("mouseover", this.onMouseOver);
|
|
|
|
elem.addEventListener("mouseout", this.onMouseOut);
|
|
|
|
}
|
|
|
|
onMouseOver(event) {
|
|
|
|
if (this.isOverElement) {
|
|
// if we're over the element, then ignore the event
|
|
// we are already measuring the speed
|
|
return;
|
|
}
|
|
|
|
this.isOverElement = true;
|
|
|
|
// after every mousemove we'll be check the distance
|
|
// between the previous and the current mouse coordinates
|
|
// if it's less than sensivity, then the speed is slow
|
|
|
|
this.prevX = event.pageX;
|
|
this.prevY = event.pageY;
|
|
this.prevTime = Date.now();
|
|
|
|
elem.addEventListener('mousemove', this.onMouseMove);
|
|
this.checkSpeedInterval = setInterval(this.trackSpeed, this.interval);
|
|
}
|
|
|
|
onMouseOut(event) {
|
|
// if left the element
|
|
if (!event.relatedTarget || !elem.contains(event.relatedTarget)) {
|
|
this.isOverElement = false;
|
|
this.elem.removeEventListener('mousemove', this.onMouseMove);
|
|
clearInterval(this.checkSpeedInterval);
|
|
if (this.isHover) {
|
|
// if there was a stop over the element
|
|
this.out.call(this.elem, event);
|
|
this.isHover = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
onMouseMove(event) {
|
|
this.lastX = event.pageX;
|
|
this.lastY = event.pageY;
|
|
this.lastTime = Date.now();
|
|
}
|
|
|
|
trackSpeed() {
|
|
|
|
let speed;
|
|
|
|
if (!this.lastTime || this.lastTime == this.prevTime) {
|
|
// cursor didn't move
|
|
speed = 0;
|
|
} else {
|
|
speed = Math.sqrt(
|
|
Math.pow(this.prevX - this.lastX, 2) +
|
|
Math.pow(this.prevY - this.lastY, 2)
|
|
) / (this.lastTime - this.prevTime);
|
|
}
|
|
|
|
if (speed < this.sensitivity) {
|
|
clearInterval(this.checkSpeedInterval);
|
|
this.isHover = true;
|
|
this.over.call(this.elem, event);
|
|
} else {
|
|
// speed fast, remember new coordinates as the previous ones
|
|
this.prevX = this.lastX;
|
|
this.prevY = this.lastY;
|
|
this.prevTime = this.lastTime;
|
|
}
|
|
}
|
|
|
|
destroy() {
|
|
elem.removeEventListener('mousemove', this.onMouseMove);
|
|
elem.removeEventListener('mouseover', this.onMouseOver);
|
|
elem.removeEventListener('mouseout', this.onMouseOut);
|
|
}
|
|
|
|
}
|