All files Joystick.js

21.42% Statements 9/42
3.57% Branches 1/28
28.57% Functions 2/7
20.51% Lines 8/39

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99                    2x     2x 22x   22x   22x                           22x                                                                           22x         22x                                              
import React from "react";
import { useState } from "react";
 
import useInterval from "use-interval";
import { useSpring, animated } from "@react-spring/web";
import { useDrag } from "@use-gesture/react";
 
import { apiUpdateMoveRaw } from "./rest";
 
 
const speedOffset = 30;
 
 
export const Joystick = (props) => {
  const [state, setState] = useState({active: false, position: {x: 0, y: 0}});
 
  const [{ x, y }, set] = useSpring(() => ({ x: 0, y: 0 }));
 
  const bind = useDrag(async ({ active, movement: [mx, my] }) => {
    let distance = Math.sqrt(Math.pow(mx, 2) + Math.pow(my, 2));
    if (active && distance > 100) {
      return;
    }
    let newPos = { x: mx, y: my };
    setState({active: active, position: newPos});
    set({ x: active ? mx : 0, y: active ? my : 0, immediate: active });
 
    if (!active) {
      await apiUpdateMoveRaw(props.address, 0, 0).catch(error => console.log(error));
    }
  })
 
  const moveToSpeeds = () => {
    const dir = (128 * state.position.y / 200) * -1;
    const angle = (128 * state.position.x / 200) * -1;
 
    let leftSpeed = (dir + angle);
    let rightSpeed = (dir - angle);
 
    // Use speed offset
    if (leftSpeed > 0) {
      leftSpeed += speedOffset;
    }
    if (rightSpeed > 0) {
      rightSpeed += speedOffset;
    }
    if (leftSpeed < 0) {
      leftSpeed -= speedOffset;
    }
    if (rightSpeed < 0) {
      rightSpeed -= speedOffset;
    }
 
    // Clamp speeds to int8 bounds
    if (leftSpeed > 127) {
      leftSpeed = 127;
    }
    if (rightSpeed > 127) {
      rightSpeed = 127;
    }
    if (leftSpeed < -128) {
      leftSpeed = -128;
    }
    if (rightSpeed < -128) {
      rightSpeed = -128;
    }
 
    return { left: leftSpeed, right: rightSpeed };
  };
 
  useInterval(async () => {
    const speeds = moveToSpeeds();
    await apiUpdateMoveRaw(props.address, speeds.left, speeds.right).catch(error => console.log(error));
  }, state.active ? 100 : null);
 
  return (
    <div style={{ height: '200px', width: '200px' }}>
      <div style={{ height: '200px', width: '200px', position: "absolute" }} role="region">
        <svg style={{ height: '199px', width: '199px'}}>
            <circle cx={99} cy={99} r={98} fill="Lavender" opacity="80%" stroke="black" strokeWidth="1" />
        </svg>
      </div>
      <div style={{ position: "relative", top: "50px", left: "50px" }}>
        <animated.div {...bind()} style={{ x, y, touchAction: 'none' }} role="button">
          <svg style={{ height: '100px', width: '100px' }}>
            <defs>
              <radialGradient id={`joystickHandleGradient${props.address}`}>
                <stop offset="5%" stopColor="MediumSlateBlue" />
                <stop offset="95%" stopColor="DarkSlateBlue" />
              </radialGradient>
            </defs>
            <circle cx={50} cy={50} r={50} opacity="80%" fill={`url('#joystickHandleGradient${props.address}')`} />
          </svg>
        </animated.div>
      </div>
    </div>
  )
}