diff --git a/src/components/CameraContianer.tsx b/src/components/CameraContianer.tsx new file mode 100644 index 0000000..96e71e1 --- /dev/null +++ b/src/components/CameraContianer.tsx @@ -0,0 +1,50 @@ +import React from "react" +import Camera from "./Camera" +import ControlPanel from "./ControlPanel" + +interface CameraContianerProps { + detectStart: (video: HTMLVideoElement) => void + canvasRef: React.LegacyRef | undefined + isModelLoaded: boolean + onChangeMode: React.ChangeEventHandler + onChangeTranslation: React.ChangeEventHandler +} + +export default function CameraContianer(props: CameraContianerProps) { + const { detectStart, canvasRef, isModelLoaded, onChangeMode, onChangeTranslation } = props + return ( +
+
+ + +
+
+ {isModelLoaded && } +
+
+ ) +} diff --git a/src/components/ControlPanel.tsx b/src/components/ControlPanel.tsx new file mode 100644 index 0000000..4303c22 --- /dev/null +++ b/src/components/ControlPanel.tsx @@ -0,0 +1,22 @@ +import React from "react" + +interface ControlPanelProps { + onChangeTranslation: React.ChangeEventHandler + onChangeMode: React.ChangeEventHandler +} + +export default function ControlPanel(props: ControlPanelProps) { + const { onChangeTranslation, onChangeMode } = props + return ( +
+
+
좌우 이동
+ +
상하 이동
+ +
크기 변경
+ +
+
+ ) +} diff --git a/src/components/PoseDetector.tsx b/src/components/PoseDetector.tsx index 4b17fcf..97a4a01 100644 --- a/src/components/PoseDetector.tsx +++ b/src/components/PoseDetector.tsx @@ -1,10 +1,11 @@ -import { useState, useEffect, useRef, useCallback } from "react" -import { Camera } from "." +import usePushNotification from "@/hooks/usePushNotification" import type { pose } from "@/utils/detector" import { detectSlope, detectTextNeck } from "@/utils/detector" import { drawPose } from "@/utils/drawer" -import usePushNotification from "@/hooks/usePushNotification" import { worker } from "@/utils/worker" +import { useCallback, useEffect, useRef, useState } from "react" +import CameraContianer from "./CameraContianer" +import TrackingResult from "./TrackingResult" const PoseDetector: React.FC = () => { const [isScriptLoaded, setIsScriptLoaded] = useState(false) @@ -14,7 +15,7 @@ const PoseDetector: React.FC = () => { const [isModelLoaded, setIsModelLoaded] = useState(false) const [mode, setMode] = useState("snapshot") const [canInit, setCanInit] = useState(false) - const [isSnapSaved, setIsSnapSaved] = useState(false); + const [isSnapSaved, setIsSnapSaved] = useState(false) const modelRef = useRef(null) const snapRef = useRef(null) const resultRef = useRef(null) @@ -69,7 +70,7 @@ const PoseDetector: React.FC = () => { await window.ml5.setBackend("webgl") } - const canInitCallback = (canInit : boolean) => { + const canInitCallback = (canInit: boolean) => { setCanInit(canInit) } @@ -77,14 +78,7 @@ const PoseDetector: React.FC = () => { (results: pose[]): void => { resultRef.current = results if (canvasRef.current) { - drawPose( - results, - canvasRef.current, - dx.current, - dy.current, - scale.current, - canInitCallback, - !!snapRef.current) + drawPose(results, canvasRef.current, dx.current, dy.current, scale.current, canInitCallback, !!snapRef.current) } if (snapRef.current) { const _slope = detectSlope(snapRef.current, results, mode === "snapshot") @@ -116,7 +110,7 @@ const PoseDetector: React.FC = () => { const detectStart = useCallback( async (video: HTMLVideoElement): Promise => { - worker.onmessage = ({ }: any) => { + worker.onmessage = ({}: any) => { if (modelRef.current) { modelRef.current.detect(video, detect) } @@ -162,21 +156,21 @@ const PoseDetector: React.FC = () => { } const onChangeTranslation = (e: React.ChangeEvent) => { - const id = e.target.id ; - if(e.target.value){ - const value = Number.parseInt(e.target.value) - switch(id){ - case 'vertical' : - dy.current = value - return - case 'horizontal' : - dx.current = value - return - case 'scale' : - scale.current = value / 100 * 2 - return - default : - } + const id = e.target.id + if (e.target.value) { + const value = Number.parseInt(e.target.value) + switch (id) { + case "vertical": + dy.current = value + return + case "horizontal": + dx.current = value + return + case "scale": + scale.current = (value / 100) * 2 + return + default: + } } } @@ -185,99 +179,95 @@ const PoseDetector: React.FC = () => { } return ( -
+ <> {isScriptError ? ( "스크립트 불러오기 실패" ) : !isScriptLoaded ? ( "스크립트 불러오는 중" ) : ( - <> - - + {isModelLoaded && ( - <> -
-
좌우 이동
- -
상하 이동
- -
크기 변경
- -
-
본 화면은 좌우가 반대로 보이고 있으니 주의하세요!
-
- -
- {mode === "snapshot" && ( - <> -
- 스냅샷 모드입니다. 올바른 자세를 하신 후에, 버튼을 눌러 촬영을 하면 해당 자세를 기준으로 부적절한 - 자세를 추적합니다! -
- { - canInit ? - isSnapSaved ? - : + + ) : ( : -
스냅샷을 찍을 수 없습니다. 가이드 라인에 맞게 자세를 잡아주세요.
- } - - )} - {mode === "skeleton" && ( - <> -
자동 모드입니다. 자동으로 부적절한 자세를 추적합니다.
-
- - + + ) + ) : ( +
+ 스냅샷을 찍을 수 없습니다. 가이드 라인에 맞게 자세를 잡아주세요. +
+ )}
- - )} - -
- 거북목 상태:  - {isTextNeck === null ? ( - "상태를 확인할 수 없습니다." - ) : isTextNeck ? ( - "거북목 상태 입니다" - ) : ( - "정상적인 자세 입니다" )} + {mode === "skeleton" && ( + <> +
자동 모드입니다. 자동으로 부적절한 자세를 추적합니다.
+
+ + +
+ + )} +
+
+
-
어깨 기울기: {slope === null ? "상태를 확인할 수 없습니다." : slope}
- +
)} - + )} - + ) } diff --git a/src/components/TrackingResult.tsx b/src/components/TrackingResult.tsx new file mode 100644 index 0000000..35812f8 --- /dev/null +++ b/src/components/TrackingResult.tsx @@ -0,0 +1,32 @@ +interface TrackingResultProps { + isTextNeck: boolean | null + slope: null | string +} + +export default function TrackingResult(props: TrackingResultProps) { + const { isTextNeck, slope } = props + return ( +
+
+ 거북목 상태:  + {isTextNeck === null ? ( + "상태를 확인할 수 없습니다." + ) : isTextNeck ? ( + 거북목 상태 입니다 + ) : ( + "정상적인 자세 입니다" + )} +
+
+ 어깨 기울기: {slope === null && 상태를 확인할 수 없습니다.} + {slope && {slope}} +
+
+ ) +}