import { MOUSE_TRAIL } from 'App/constants/storageKeys'; import type Screen from '../Screen/Screen'; import type { MouseMove } from '../messages'; import { HOVER_CLASSNAME } from '../messages/rewriter/constants'; import ListWalker from '../../common/ListWalker'; import MouseTrail from '../addons/MouseTrail'; import styles from './trail.module.css'; export default class MouseMoveManager extends ListWalker { private hoverElements: Array = []; private mouseTrail: MouseTrail | undefined; private readonly removeMouseTrail: boolean = false; constructor(private screen: Screen) { super(); const canvas = document.createElement('canvas'); canvas.id = 'openreplay-mouse-trail'; canvas.className = styles.canvas; this.removeMouseTrail = localStorage.getItem(MOUSE_TRAIL) === 'false'; if (!this.removeMouseTrail) { this.mouseTrail = new MouseTrail(canvas); } this.screen.overlay.appendChild(canvas); this.mouseTrail?.createContext(); const updateSize = (w: number, h: number) => this.mouseTrail?.resizeCanvas(w, h); this.screen.setOnUpdate(updateSize); } private getCursorTargets() { return this.screen.getElementsFromInternalPoint(this.current!); } private updateHover(): void { const curHoverElements = this.getCursorTargets(); const diffAdd = curHoverElements.filter( (elem) => !this.hoverElements.includes(elem), ); const diffRemove = this.hoverElements.filter( (elem) => !curHoverElements.includes(elem), ); this.hoverElements = curHoverElements; diffAdd.forEach((elem) => { elem.classList.add(HOVER_CLASSNAME); }); diffRemove.forEach((elem) => { elem.classList.remove(HOVER_CLASSNAME); }); } reset(): void { this.hoverElements.length = 0; } move(t: number) { const lastMouseMove = this.moveGetLast(t); if (lastMouseMove) { this.screen.cursor.move(lastMouseMove); // window.getComputedStyle(this.screen.getCursorTarget()).cursor === 'pointer' // might influence performance though this.updateHover(); this.mouseTrail?.leaveTrail(lastMouseMove.x, lastMouseMove.y); } } }