Skip to content

Commit

Permalink
Handle touch
Browse files Browse the repository at this point in the history
  • Loading branch information
jackyef committed Mar 9, 2024
1 parent 0289eee commit 5f21041
Showing 1 changed file with 56 additions and 10 deletions.
66 changes: 56 additions & 10 deletions src/components/absurd-components/BallisticSlider/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { VolumeIcon, Volume1Icon, Volume2Icon } from 'lucide-react';
import { css } from 'goober';
import { MouseEventHandler, useEffect, useRef, useState } from 'react';
import {
MouseEventHandler,
TouchEventHandler,
useEffect,
useRef,
useState,
} from 'react';
import { useAnimate, motion } from 'framer-motion';

import { getHslaColor } from '@/lib/styles/colors';
Expand Down Expand Up @@ -116,7 +122,7 @@ export const BallisticSlider = ({
}
};

const handleMouseMove: MouseEventHandler = (e) => {
const handlePointerMove = (x: number, y: number) => {
if (state !== 'dragging') return;

const c = containerRef.current;
Expand All @@ -125,10 +131,6 @@ export const BallisticSlider = ({

if (!c || !b || !p) return;

const containerRect = c.getBoundingClientRect();
const mouseX = e.clientX - containerRect.left;
const mouseY = e.clientY - containerRect.top;

// Assume the container has a height of y and width of x
// The max distance for the projectile will be x
// minus some margins
Expand All @@ -147,8 +149,7 @@ export const BallisticSlider = ({
const buttonOriginX = b.offsetLeft + b.offsetWidth / 2;
const buttonOriginY = height / 2;
const angleDegree =
Math.atan2(mouseY - buttonOriginY, mouseX - buttonOriginX) *
-(180 / Math.PI);
Math.atan2(y - buttonOriginY, x - buttonOriginX) * -(180 / Math.PI);
const vy = initialVelocity * Math.sin(angleDegree * (Math.PI / 180));
const timeInAir = angleDegree < 0 ? 0 : (2 * vy) / 4;

Expand All @@ -163,8 +164,8 @@ export const BallisticSlider = ({
// These are for the debugger UIs
c.style.setProperty('--button-x', `${buttonOriginX}px`);
c.style.setProperty('--button-y', `${buttonOriginY}px`);
c.style.setProperty('--mouse-x', `${mouseX}px`);
c.style.setProperty('--mouse-y', `${mouseY}px`);
c.style.setProperty('--mouse-x', `${x}px`);
c.style.setProperty('--mouse-y', `${y}px`);
c.style.setProperty('--angle-degree', `'${angleDegree.toFixed(0)}°'`);
c.style.setProperty('--projected-distance', `${projectedDistance}px`);
c.style.setProperty('--slider-value', `'${sliderValue.toFixed(0)}%'`);
Expand All @@ -190,12 +191,56 @@ export const BallisticSlider = ({
);
};

const handleMouseMove: MouseEventHandler = (e) => {
if (state !== 'dragging') return;

const c = containerRef.current;

if (!c) return;

const containerRect = c.getBoundingClientRect();
const mouseX = e.clientX - containerRect.left;
const mouseY = e.clientY - containerRect.top;

handlePointerMove(mouseX, mouseY);
};

// Touch events have to be handled differently.
// We need to prevent touchmove causing scrolling by doing e.preventDefault().
// This requires the eventListener to be non-passive.
// React automatically sets passive to true, when passing onTouchMove prop,
// so we have to bypass it and addEventListener to the DOM node directly.
useEffect(() => {
const c = containerRef.current;
if (!c) return;
if (state !== 'dragging') return;

const handleTouchMove = (e: TouchEvent) => {
e.preventDefault();

const containerRect = c.getBoundingClientRect();
const touch = e.touches[0] || e.changedTouches[0];

const mouseX = touch.pageX - containerRect.left;
const mouseY = touch.pageY - containerRect.top;

handlePointerMove(mouseX, mouseY);
};

c.addEventListener('touchmove', handleTouchMove, { passive: false });

return () => {
c.removeEventListener('touchmove', handleTouchMove);
};
}, [state, handlePointerMove]);

const showDebugger = debug && state !== 'idle';

return (
<div
ref={containerRef}
onMouseUpCapture={startFiring}
onTouchEndCapture={startFiring}
onMouseMove={handleMouseMove}
className={cn(
css`
Expand All @@ -214,6 +259,7 @@ export const BallisticSlider = ({
draggable={false}
ref={buttonRef}
onMouseDown={startDragging}
onTouchStart={startDragging}
>
<motion.div
initial="idle"
Expand Down

0 comments on commit 5f21041

Please sign in to comment.