Javascript

[React Native] 터치한 곳의 좌표 구하고 각도 구하기

joy_lee 2022. 2. 16. 16:33

타이머를 터치해서 시간을 설정할 수 있도록 만들려고 한다.

Progress.Pie는 1과 0 사이의 수를 입력받아 색칠해준다. 0이면 비어있고, 1이면 모두 차 있는 파이를 나타낸다.

1
<Progress.Pie progress={0.3} size={300} color={theme.red} />
cs

 

화면 터치로 파이를 채우려면 알아야 될 것이 있다.

1. 파이 내에서 터치 이벤트가 발생한 위치

2. 각도

위치는 각도를알기 위해서 알아야하는 정보이고, 각도를 알아야 (각도 / 360)으로 progress값을 전달해 파이를 채울 수 있다.

 

한 점만 움직이고, 그 점과 y축과의 각도만 구하면 된다.

1. 터치 이벤트가 발생한 위치 알아내기

터치를 인식하기 위해 TouchableOpacity로 Progress.Pie를 감싸주었다. onPress로 setTime이라는 함수를 넘겨주었다.

1
2
3
4
5
6
7
8
9
const Timer = () => {
  const [progress, setProgress] = useState(0.3);
 
  return (
    <TouchableOpacity onPress={setTime}>
        <Progress.Pie progress={progress} size={300} color={theme.red} />
      </TouchableOpacity>
  )
}
cs

setTime이라는 함수는 터치가 발생한 위치를 확인해 progress를 계산하는 함수이다.

1
2
3
4
5
6
7
8
const setTime = (e) => {
 const { locationX, locationY } = e.nativeEvent;
 const x = locationX - 150;
 const y = 150 - locationY;

 const newProgress = getAngle(x, y) / 360;
 setProgress(newProgress);
};
cs

TouchableOpacity를 터치했을 때 발생하는 이벤트에는 위치정보를 포함하고 있다.

e.nativeEvent를 console에서 확인해보면 다음과 같은 정보를 가지고있다.

여기에서 pageX, pageY는 화면안에서의 위치를 나타내고, locationX와 locationY는 touchableOpacity안에서의 위치를 나타낸다.

2. 각도 구하기

(locationX, locationY)는 왼쪽위를 (0, 0)으로 시작해 오른쪽아래가 (300, 300)으로 정해져있다.

중심축을 파이의 중간으로 하고, y축의 방향을 계산하기 쉽게 바꿔준다.

변환한 값을 getAngle(x, y)에 입력한다.

 

getAngle에서는 atan을 이용해 각도를 구한다.

atan은 두 변의 길이를 알 때 삼각형의 각도를 구할 수 있다.

arctan은 x축을 기준으로 구하게 되므로 x가 0보다 클 때와 0보다 작을 때를 나눠서 계산해야 한다.

이를 코드로 작성하면 아래와 같다.

1
2
3
4
5
6
7
8
9
10
const getAngle = (x, y) => {
  let angle = 0;
  if (x >= 0) {
    angle = 90 - Math.atan(y / x) * (180 / Math.PI);
  } else {
    angle = 270 - Math.atan(y / x) * (180 / Math.PI);
  }
  // 시계눈금이기 때문에 6의 배수여야 한다.
  return Math.ceil(angle/6)*6;
};
cs

구한 각도는 시간을 나타내야 하고 60분이 가능하도록 계산된 각도와 가장 가까운 6의배수로 계산해서 출력한다.

시간을 설정할 때 0분은 필요 없고, 60분은 가능해야 하므로 올림해서 구한다.

 

이렇게 구한 각도를 가지고 setTime에서 progress와 minute를 계산해 설정한다.

1
2
3
4
5
6
7
8
9
10
const [minute, setMinute] = useState(Math.ceil(progress * 60));
const [second, setSecond] = useState(0);
 
const setTime = (e) => {
// 생략..
  const newProgress = getAngle(x, y) / 360;
  setProgress(newProgress);
  setMinute(Math.ceil(newProgress * 60));
  setSecond(0);
};
cs

 

전체적인 코드는 아래와 같다.

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
const Timer = () => {
  const [progress, setProgress] = useState(0.3);
  const [minute, setMinute] = useState(Math.ceil(progress * 60));
  const [second, setSecond] = useState(0);
 
  const getAngle = (x, y) => {
    let angle = 0;
    if (x >= 0) {
      angle = 90 - Math.atan(y / x) * (180 / Math.PI);
    } else {
      angle = 270 - Math.atan(y / x) * (180 / Math.PI);
    }
    // 시계눈금이기 때문에 6의 배수여야 한다.
    return Math.ceil(angle/6)*6;
  };
 
  const setTime = (e) => {
    console.log(e.nativeEvent);
    const { locationX, locationY } = e.nativeEvent;
    const x = locationX - 150;
    const y = 150 - locationY;
 
    const newProgress = getAngle(x, y) / 360;
    setProgress(newProgress);
    setMinute(Math.ceil(newProgress * 60));
    setSecond(0);
  };
 
  return (
      <TouchableOpacity onPress={setTime}>
        <Progress.Pie progress={progress} size={300} color={theme.red} />
      </TouchableOpacity>
  );
};
cs

 

이렇게 터치를 통해 타이머 시간을 설정하도록 코드를 작성해보았다. 각도를 구하는게 결국은 수학이어서 자료를 찾으며 오랜만에 삼각함수를 보게됐다. 세 점 사이의 각도를 구하는 것으로 생각했으나 어차피 두 점은 고정되어있는 것이어서 더 쉽게 계산할 수 있었다. 세 점 사이의 각도는 참고한 페이지를 확인하면 쉽게 알 수 있다.

 

 

참고한 페이지

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=tobsysco&logNo=90189688655 

 

[이론] 세점 사이의 각도 (두 직선 사이의 각도) 구하기..

세 점 사이의 각도를 구하는 방법을 알아보자. 세점이라 함은 한점을 교점으로한 두 직선을 뜻하며 그 사잇...

blog.naver.com

https://velog.io/@davelee/arctan을-활용한-각도구하기

 

arctan을 활용한 각도 구하기

캔버스나 뷰에서 이런저런 장난을 치다 보면, 두 점 사이의 각도를 구해야 할 때가 있다. 이럴 때는 삼각함수 중 arctan을 이용해보자.삼각함수중 tan을 이용하면 특정한 각도에서의 세로/가로의

velog.io