This commit is contained in:
@@ -180,6 +180,7 @@ export class InteractiveBackground implements AfterViewInit, OnDestroy {
|
||||
private pointerX = 0;
|
||||
private pointerY = 0;
|
||||
private pointerActive = false;
|
||||
private activeTouchId: number | null = null;
|
||||
private reducedMotion = false;
|
||||
private mediaQuery!: MediaQueryList;
|
||||
|
||||
@@ -203,25 +204,61 @@ export class InteractiveBackground implements AfterViewInit, OnDestroy {
|
||||
this.isCursorVisible = this.getMediaQuery('(pointer: fine)').matches;
|
||||
|
||||
const onResize = () => this.resizeCanvas();
|
||||
const onMove = (event: PointerEvent) => this.handlePointerMove(event);
|
||||
const onLeave = () => this.handlePointerLeave();
|
||||
const onDown = () => (this.isPointerDown = true);
|
||||
const onUp = () => (this.isPointerDown = false);
|
||||
const supportsPointerEvents = 'PointerEvent' in window;
|
||||
const onPointerMove = (event: PointerEvent) => this.handlePointerMove(event);
|
||||
const onPointerLeave = () => this.handlePointerLeave();
|
||||
const onPointerDown = (event: PointerEvent) => this.handlePointerDown(event);
|
||||
const onPointerUp = (event: PointerEvent) => this.handlePointerUp(event);
|
||||
const onPointerCancel = () => this.handlePointerLeave();
|
||||
|
||||
const onMouseMove = (event: MouseEvent) => this.handleMouseMove(event);
|
||||
const onMouseLeave = () => this.handlePointerLeave();
|
||||
const onMouseDown = (event: MouseEvent) => this.handleMouseDown(event);
|
||||
const onMouseUp = () => this.handleMouseUp();
|
||||
|
||||
const onTouchStart = (event: TouchEvent) => this.handleTouchStart(event);
|
||||
const onTouchMove = (event: TouchEvent) => this.handleTouchMove(event);
|
||||
const onTouchEnd = (event: TouchEvent) => this.handleTouchEnd(event);
|
||||
const onTouchCancel = () => this.handlePointerLeave();
|
||||
|
||||
const onMotionChange = (event: MediaQueryListEvent) => this.handleMotionPreferenceChange(event.matches);
|
||||
|
||||
window.addEventListener('resize', onResize);
|
||||
window.addEventListener('pointermove', onMove, { passive: true });
|
||||
window.addEventListener('pointerleave', onLeave);
|
||||
window.addEventListener('pointerdown', onDown, { passive: true });
|
||||
window.addEventListener('pointerup', onUp, { passive: true });
|
||||
|
||||
if (supportsPointerEvents) {
|
||||
window.addEventListener('pointermove', onPointerMove, { passive: true });
|
||||
window.addEventListener('pointerleave', onPointerLeave);
|
||||
window.addEventListener('pointerdown', onPointerDown, { passive: true });
|
||||
window.addEventListener('pointerup', onPointerUp, { passive: true });
|
||||
window.addEventListener('pointercancel', onPointerCancel, { passive: true });
|
||||
} else {
|
||||
window.addEventListener('mousemove', onMouseMove, { passive: true });
|
||||
window.addEventListener('mouseleave', onMouseLeave);
|
||||
window.addEventListener('mousedown', onMouseDown, { passive: true });
|
||||
window.addEventListener('mouseup', onMouseUp, { passive: true });
|
||||
window.addEventListener('touchstart', onTouchStart, { passive: true });
|
||||
window.addEventListener('touchmove', onTouchMove, { passive: true });
|
||||
window.addEventListener('touchend', onTouchEnd, { passive: true });
|
||||
window.addEventListener('touchcancel', onTouchCancel, { passive: true });
|
||||
}
|
||||
|
||||
this.mediaQuery.addEventListener('change', onMotionChange);
|
||||
|
||||
this.destroyCallbacks = [
|
||||
() => window.removeEventListener('resize', onResize),
|
||||
() => window.removeEventListener('pointermove', onMove),
|
||||
() => window.removeEventListener('pointerleave', onLeave),
|
||||
() => window.removeEventListener('pointerdown', onDown),
|
||||
() => window.removeEventListener('pointerup', onUp),
|
||||
() => window.removeEventListener('pointermove', onPointerMove),
|
||||
() => window.removeEventListener('pointerleave', onPointerLeave),
|
||||
() => window.removeEventListener('pointerdown', onPointerDown),
|
||||
() => window.removeEventListener('pointerup', onPointerUp),
|
||||
() => window.removeEventListener('pointercancel', onPointerCancel),
|
||||
() => window.removeEventListener('mousemove', onMouseMove),
|
||||
() => window.removeEventListener('mouseleave', onMouseLeave),
|
||||
() => window.removeEventListener('mousedown', onMouseDown),
|
||||
() => window.removeEventListener('mouseup', onMouseUp),
|
||||
() => window.removeEventListener('touchstart', onTouchStart),
|
||||
() => window.removeEventListener('touchmove', onTouchMove),
|
||||
() => window.removeEventListener('touchend', onTouchEnd),
|
||||
() => window.removeEventListener('touchcancel', onTouchCancel),
|
||||
() => this.mediaQuery.removeEventListener('change', onMotionChange),
|
||||
];
|
||||
}
|
||||
@@ -282,18 +319,115 @@ export class InteractiveBackground implements AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
private handlePointerMove(event: PointerEvent): void {
|
||||
this.pointerX = event.clientX;
|
||||
this.pointerY = event.clientY;
|
||||
this.pointerActive = true;
|
||||
this.cursorTransform = `translate3d(${event.clientX}px, ${event.clientY}px, 0)`;
|
||||
if (event.pointerType === 'touch' && this.activeTouchId !== null && event.pointerId !== this.activeTouchId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updatePointer(event.clientX, event.clientY, true);
|
||||
}
|
||||
|
||||
private handlePointerDown(event: PointerEvent): void {
|
||||
if (event.pointerType === 'touch') {
|
||||
this.activeTouchId = event.pointerId;
|
||||
}
|
||||
|
||||
this.isPointerDown = true;
|
||||
this.updatePointer(event.clientX, event.clientY, true);
|
||||
}
|
||||
|
||||
private handlePointerUp(event: PointerEvent): void {
|
||||
this.isPointerDown = false;
|
||||
|
||||
if (event.pointerType === 'touch') {
|
||||
if (this.activeTouchId !== null && event.pointerId !== this.activeTouchId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.activeTouchId = null;
|
||||
this.pointerActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.updatePointer(event.clientX, event.clientY, true);
|
||||
}
|
||||
|
||||
private handleMouseMove(event: MouseEvent): void {
|
||||
this.updatePointer(event.clientX, event.clientY, true);
|
||||
}
|
||||
|
||||
private handleMouseDown(event: MouseEvent): void {
|
||||
this.isPointerDown = true;
|
||||
this.updatePointer(event.clientX, event.clientY, true);
|
||||
}
|
||||
|
||||
private handleMouseUp(): void {
|
||||
this.isPointerDown = false;
|
||||
}
|
||||
|
||||
private handleTouchStart(event: TouchEvent): void {
|
||||
const touch = event.changedTouches.item(0);
|
||||
if (!touch) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.activeTouchId = touch.identifier;
|
||||
this.isPointerDown = true;
|
||||
this.updatePointer(touch.clientX, touch.clientY, true);
|
||||
}
|
||||
|
||||
private handleTouchMove(event: TouchEvent): void {
|
||||
if (this.activeTouchId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const touch = this.findTouch(event.touches, this.activeTouchId);
|
||||
if (!touch) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updatePointer(touch.clientX, touch.clientY, true);
|
||||
}
|
||||
|
||||
private handleTouchEnd(event: TouchEvent): void {
|
||||
if (this.activeTouchId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const touch = this.findTouch(event.changedTouches, this.activeTouchId);
|
||||
if (!touch) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isPointerDown = false;
|
||||
this.activeTouchId = null;
|
||||
this.pointerActive = false;
|
||||
}
|
||||
|
||||
private handlePointerLeave(): void {
|
||||
this.pointerActive = false;
|
||||
this.isPointerDown = false;
|
||||
this.activeTouchId = null;
|
||||
this.cursorTransform = 'translate3d(-9999px, -9999px, 0)';
|
||||
}
|
||||
|
||||
private updatePointer(x: number, y: number, active: boolean): void {
|
||||
this.pointerX = x;
|
||||
this.pointerY = y;
|
||||
this.pointerActive = active;
|
||||
this.cursorTransform = `translate3d(${x}px, ${y}px, 0)`;
|
||||
}
|
||||
|
||||
private findTouch(touches: TouchList, identifier: number): Touch | null {
|
||||
for (let index = 0; index < touches.length; index += 1) {
|
||||
const touch = touches.item(index);
|
||||
if (touch && touch.identifier === identifier) {
|
||||
return touch;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private syncPointer(): void {
|
||||
this.particleEngine?.setPointer({
|
||||
x: this.pointerX,
|
||||
@@ -342,3 +476,4 @@ export class InteractiveBackground implements AfterViewInit, OnDestroy {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user