diff --git a/src/asset/image/MapCurrent.png b/src/asset/image/MapCurrent.png new file mode 100644 index 0000000..3862b1e Binary files /dev/null and b/src/asset/image/MapCurrent.png differ diff --git a/src/components/map/KakaoMap.tsx b/src/components/map/KakaoMap.tsx index 81f76ff..76aa506 100644 --- a/src/components/map/KakaoMap.tsx +++ b/src/components/map/KakaoMap.tsx @@ -1,11 +1,16 @@ import { useEffect, useState } from 'react'; +import { useRecoilValue, useSetRecoilState } from 'recoil'; import styled from 'styled-components'; -import { KakaoMapInfo } from '../../types/map'; +import MapCurrent from '../../asset/image/MapCurrent.png'; +import { floggingInfoState, mapLocationInfoState } from '../../recoil/atom'; +import { KakaoMapLocation } from '../../types/map'; +import { getDistanceKm } from '../../utils/getDistanceKm'; const KakaoMap = () => { - const [map, setMap] = useState({}); - const [kakaoMapInfo, setKakaoMapInfo] = useState(); + const mapLocationInfo = useRecoilValue(mapLocationInfoState); + const setFloggingInfo = useSetRecoilState(floggingInfoState); + const [kakaoMapInfo, setKakaoMapInfo] = useState(); const { kakao } = window; useEffect(() => { @@ -23,7 +28,30 @@ const KakaoMap = () => { level: 3, }; - setMap(new kakao.maps.Map(container, options)); + const map = new kakao.maps.Map(container, options); + + const markerImgSrc = MapCurrent; + const markerImgSize = new kakao.maps.Size(window.screen.width * 0.08, window.screen.width * 0.08); + const markerImg = new kakao.maps.MarkerImage(markerImgSrc, markerImgSize); + const markerPosition = new kakao.maps.LatLng(kakaoMapInfo.latitude, kakaoMapInfo.longitude); + const marker = new kakao.maps.Marker({ + position: markerPosition, + image: markerImg, + }); + + const linePath = mapLocationInfo.map((location) => new kakao.maps.LatLng(location.latitude, location.longitude)); + const kakaoPolyline = new kakao.maps.Polyline({ + path: linePath, + strokeWeight: 5, + strokeColor: '#EF8D8A', + strokeOpacity: 0.7, + strokeStyle: 'solid', + }); + + marker.setMap(map); + kakaoPolyline.setMap(map); + + setFloggingInfo((prev) => ({ ...prev, distance: getDistanceKm(mapLocationInfo) })); } }, [kakaoMapInfo]); diff --git a/src/components/map/RunningControl.tsx b/src/components/map/RunningControl.tsx index ee9ad78..f3e3634 100644 --- a/src/components/map/RunningControl.tsx +++ b/src/components/map/RunningControl.tsx @@ -4,6 +4,7 @@ import styled from 'styled-components'; import { IcRunning } from '../../asset/icon'; import useCouter from '../../lib/hooks/useCouter'; +import useCurrentLocation from '../../lib/hooks/useCurrentLocation'; import { floggingInfoState } from '../../recoil/atom'; import { getDateParse } from '../../utils/dateParse'; import JupgoButton from './JupgoButton'; @@ -12,18 +13,23 @@ const RunningControl = () => { const [isFloggingPause, setIsFloggintPause] = useState(false); const [floggingInfo, setFloggingInfo] = useRecoilState(floggingInfoState); const { count, start, stop } = useCouter(0, 1000); + const { startRecordLocation, stopRecordLocation } = useCurrentLocation(); + const { distance, duration } = floggingInfo; const handleFloggingStart = () => { start(); + startRecordLocation(); setIsFloggintPause(!isFloggingPause); }; const handleFloggingPause = () => { stop(); + stopRecordLocation(); setIsFloggintPause(!isFloggingPause); }; const handleFloggingStop = () => { stop(); + stopRecordLocation(); setFloggingInfo({ ...floggingInfo }); }; diff --git a/src/lib/hooks/useCurrentLocation.tsx b/src/lib/hooks/useCurrentLocation.tsx new file mode 100644 index 0000000..48ec7ec --- /dev/null +++ b/src/lib/hooks/useCurrentLocation.tsx @@ -0,0 +1,34 @@ +import { useCallback, useRef } from 'react'; +import { useRecoilState } from 'recoil'; + +import { mapLocationInfoState } from '../../recoil/atom'; + +const useCurrentLocation = () => { + const [mapLocationInfo, setMapLocationInfo] = useRecoilState(mapLocationInfoState); + const intervalRef = useRef(null); + + const startRecordLocation = useCallback(() => { + if (intervalRef.current) return; + intervalRef.current = setInterval(() => { + if (navigator.geolocation) { + navigator.geolocation.getCurrentPosition(({ coords }) => { + const filterMapLocationInfo = mapLocationInfo.filter( + ({ latitude, longitude }) => coords.latitude !== latitude && coords.longitude !== longitude, + ); + if (filterMapLocationInfo.length === mapLocationInfo.length) + setMapLocationInfo([...mapLocationInfo, { latitude: coords.latitude, longitude: coords.longitude }]); + }); + } + }, 1000); + }, []); + + const stopRecordLocation = useCallback(() => { + if (!intervalRef.current) return; + clearInterval(intervalRef.current); + intervalRef.current = null; + }, []); + + return { startRecordLocation, stopRecordLocation }; +}; + +export default useCurrentLocation; diff --git a/src/recoil/atom.ts b/src/recoil/atom.ts index 6d315b1..1216370 100644 --- a/src/recoil/atom.ts +++ b/src/recoil/atom.ts @@ -2,6 +2,7 @@ import { atom } from 'recoil'; import { recoilPersist } from 'recoil-persist'; import { FloggingData } from '../types/flogging'; +import { KakaoMapLocation } from '../types/map'; const { persistAtom } = recoilPersist(); @@ -16,3 +17,11 @@ export const floggingInfoState = atom({ }, effects_UNSTABLE: [persistAtom], }); + +export const mapLocationInfoState = atom({ + key: 'mapLocationInfo', + default: [ + { latitude: 37.5017936, longitude: 126.8831826 }, + { latitude: 37.5, longitude: 126.8841 }, + ], +}); diff --git a/src/types/map.ts b/src/types/map.ts index 599b999..fc09a96 100644 --- a/src/types/map.ts +++ b/src/types/map.ts @@ -3,7 +3,7 @@ declare global { kakao: any; } } -export interface KakaoMapInfo { +export interface KakaoMapLocation { latitude: number; longitude: number; } diff --git a/src/utils/getDistanceKm.ts b/src/utils/getDistanceKm.ts new file mode 100644 index 0000000..b98e558 --- /dev/null +++ b/src/utils/getDistanceKm.ts @@ -0,0 +1,23 @@ +import { KakaoMapLocation } from '../types/map'; +const RADIUS_EARTH_KM = 6371; +const degreesToRadians = (deg: number) => { + return deg * (Math.PI / 180); +}; +export const getDistanceKm = (mapLocationList: KakaoMapLocation[]) => { + return mapLocationList.reduce((distance, currentLocation, index) => { + if (index) { + const startLatRads = degreesToRadians(currentLocation.latitude); + const startLongRads = degreesToRadians(currentLocation.longitude); + const destLatRads = degreesToRadians(mapLocationList[index - 1].latitude); + const destLongRads = degreesToRadians(mapLocationList[index - 1].longitude); + + const calDistance = + Math.acos( + Math.sin(startLatRads) * Math.sin(destLatRads) + + Math.cos(startLatRads) * Math.cos(destLatRads) * Math.cos(startLongRads - destLongRads), + ) * RADIUS_EARTH_KM; + return distance + Number(calDistance.toFixed(2)); + } + return distance; + }, 0); +};