This commit is contained in:
@@ -180,6 +180,7 @@ export class InteractiveBackground implements AfterViewInit, OnDestroy {
|
|||||||
private pointerX = 0;
|
private pointerX = 0;
|
||||||
private pointerY = 0;
|
private pointerY = 0;
|
||||||
private pointerActive = false;
|
private pointerActive = false;
|
||||||
|
private activeTouchId: number | null = null;
|
||||||
private reducedMotion = false;
|
private reducedMotion = false;
|
||||||
private mediaQuery!: MediaQueryList;
|
private mediaQuery!: MediaQueryList;
|
||||||
|
|
||||||
@@ -203,25 +204,61 @@ export class InteractiveBackground implements AfterViewInit, OnDestroy {
|
|||||||
this.isCursorVisible = this.getMediaQuery('(pointer: fine)').matches;
|
this.isCursorVisible = this.getMediaQuery('(pointer: fine)').matches;
|
||||||
|
|
||||||
const onResize = () => this.resizeCanvas();
|
const onResize = () => this.resizeCanvas();
|
||||||
const onMove = (event: PointerEvent) => this.handlePointerMove(event);
|
const supportsPointerEvents = 'PointerEvent' in window;
|
||||||
const onLeave = () => this.handlePointerLeave();
|
const onPointerMove = (event: PointerEvent) => this.handlePointerMove(event);
|
||||||
const onDown = () => (this.isPointerDown = true);
|
const onPointerLeave = () => this.handlePointerLeave();
|
||||||
const onUp = () => (this.isPointerDown = false);
|
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);
|
const onMotionChange = (event: MediaQueryListEvent) => this.handleMotionPreferenceChange(event.matches);
|
||||||
|
|
||||||
window.addEventListener('resize', onResize);
|
window.addEventListener('resize', onResize);
|
||||||
window.addEventListener('pointermove', onMove, { passive: true });
|
|
||||||
window.addEventListener('pointerleave', onLeave);
|
if (supportsPointerEvents) {
|
||||||
window.addEventListener('pointerdown', onDown, { passive: true });
|
window.addEventListener('pointermove', onPointerMove, { passive: true });
|
||||||
window.addEventListener('pointerup', onUp, { 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.mediaQuery.addEventListener('change', onMotionChange);
|
||||||
|
|
||||||
this.destroyCallbacks = [
|
this.destroyCallbacks = [
|
||||||
() => window.removeEventListener('resize', onResize),
|
() => window.removeEventListener('resize', onResize),
|
||||||
() => window.removeEventListener('pointermove', onMove),
|
() => window.removeEventListener('pointermove', onPointerMove),
|
||||||
() => window.removeEventListener('pointerleave', onLeave),
|
() => window.removeEventListener('pointerleave', onPointerLeave),
|
||||||
() => window.removeEventListener('pointerdown', onDown),
|
() => window.removeEventListener('pointerdown', onPointerDown),
|
||||||
() => window.removeEventListener('pointerup', onUp),
|
() => 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),
|
() => this.mediaQuery.removeEventListener('change', onMotionChange),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -282,18 +319,115 @@ export class InteractiveBackground implements AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private handlePointerMove(event: PointerEvent): void {
|
private handlePointerMove(event: PointerEvent): void {
|
||||||
this.pointerX = event.clientX;
|
if (event.pointerType === 'touch' && this.activeTouchId !== null && event.pointerId !== this.activeTouchId) {
|
||||||
this.pointerY = event.clientY;
|
return;
|
||||||
this.pointerActive = true;
|
}
|
||||||
this.cursorTransform = `translate3d(${event.clientX}px, ${event.clientY}px, 0)`;
|
|
||||||
|
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 {
|
private handlePointerLeave(): void {
|
||||||
this.pointerActive = false;
|
this.pointerActive = false;
|
||||||
this.isPointerDown = false;
|
this.isPointerDown = false;
|
||||||
|
this.activeTouchId = null;
|
||||||
this.cursorTransform = 'translate3d(-9999px, -9999px, 0)';
|
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 {
|
private syncPointer(): void {
|
||||||
this.particleEngine?.setPointer({
|
this.particleEngine?.setPointer({
|
||||||
x: this.pointerX,
|
x: this.pointerX,
|
||||||
@@ -342,3 +476,4 @@ export class InteractiveBackground implements AfterViewInit, OnDestroy {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user