en.javascript.info/1-js/02-b/1-b1/2-hoverintent/solution/hoverIntent.js
Volodymyr Shevchuk fdc015e1fa Last changes
2021-05-03 15:15:32 +03:00

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);
}
}