From 5fb34289f3d7dca644013140257e4b9506622a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=83=81=ED=98=84?= Date: Thu, 4 Jan 2024 11:03:34 +0900 Subject: [PATCH] =?UTF-8?q?=EB=B9=84=ED=96=89=20=EC=8B=9C=EB=AC=BC?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=85=98=20=EC=8A=AC=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=93=9C=20=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../simulation/AnalysisSimulationDetail.js | 90 ++++++++++++++++-- .../simulation/AnalysisSimulatorSlider.js | 22 +++-- .../simulator/AnalysisSimulationContainer.js | 92 ++++++++++--------- 3 files changed, 143 insertions(+), 61 deletions(-) diff --git a/src/components/analysis/simulation/AnalysisSimulationDetail.js b/src/components/analysis/simulation/AnalysisSimulationDetail.js index 97f46a31..64c406d2 100644 --- a/src/components/analysis/simulation/AnalysisSimulationDetail.js +++ b/src/components/analysis/simulation/AnalysisSimulationDetail.js @@ -1,18 +1,47 @@ import { useRTL } from '@hooks/useRTL'; import '@styles/react/libs/noui-slider/noui-slider.scss'; import moment from 'moment'; -import React from 'react'; +import React, { useRef, useEffect, useState } from 'react'; import { X } from 'react-feather'; import { AiFillCaretRight, AiOutlinePause } from 'react-icons/ai'; +import { IoSettings } from 'react-icons/io5'; import ScrollContainer from 'react-indiana-drag-scroll'; -import { Badge, Button } from 'reactstrap'; +import { + Badge, + Button, + UncontrolledDropdown, + DropdownToggle, + DropdownMenu, + DropdownItem +} from 'reactstrap'; import drone_img from '../../../assets/images/drone.jpg'; import { ReactComponent as Simulation_icon } from '../../../assets/images/simulation_arrow.svg'; import { IMG_PATH } from '../../../configs/constants'; import AnalysisSimulatorSlider from './AnalysisSimulatorSlider'; + export const AnalysisSimulationDetail = props => { // 슬라이드 진행 방향 const [isRtl, setIsRtl] = useRTL(); + // 슬라이드 Ref + const scrollContainerRef = useRef(); + + // 슬라이드 포커스 + useEffect(() => { + const focusRes = document.querySelector('.date-num-focus'); + + const container = scrollContainerRef.current.getElement(); + container.scrollTo({ + left: focusRes?.offsetLeft - 120, + behavior: 'smooth' + }); + }, [props.timeCd]); + + // 소수점 6자리에서 반올림 하는 함수 + const truncateToSixDecimalPlaces = number => { + const decimalPlaces = 6; + const multiplier = Math.pow(10, decimalPlaces); + return Math.round(number * multiplier) / multiplier; + }; return (
@@ -56,7 +85,7 @@ export const AnalysisSimulationDetail = props => { 시작일시 - {props.data?.cntrlStDtv + {props.data?.cntrlStDt ? moment(props.data?.cntrlStDt).format( 'MM월DD일 HH:mm:ss' ) @@ -125,9 +154,10 @@ export const AnalysisSimulationDetail = props => {
좌표(위도/경도) - {props.info?.lon ? props.info?.lon + ' / ' : '-'} - - {props.info?.lat} + {props.info?.lon + ? truncateToSixDecimalPlaces(props.info?.lon) + ' / ' + : '-'} + {truncateToSixDecimalPlaces(props.info?.lat)}
@@ -183,6 +213,48 @@ export const AnalysisSimulationDetail = props => { )} + + + + + + 재생 속도 + props.setSpeed(1000)} + style={{ cursor: 'pointer' }} + className={props.speed === 1000 ? 'date-num-focus' : ''} + > + 보통 + + props.setSpeed(1000 / 2)} + style={{ cursor: 'pointer' }} + className={props.speed === 500 ? 'date-num-focus' : ''} + > + 2배속 + + props.setSpeed(1000 / 4)} + style={{ cursor: 'pointer' }} + className={props.speed === 250 ? 'date-num-focus' : ''} + > + 4배속 + + props.setSpeed(1000 / 8)} + style={{ cursor: 'pointer' }} + className={props.speed === 125 ? 'date-num-focus' : ''} + > + 8배속 + + + { />
- +
diff --git a/src/components/analysis/simulation/AnalysisSimulatorSlider.js b/src/components/analysis/simulation/AnalysisSimulatorSlider.js index b26f7964..79b157a9 100644 --- a/src/components/analysis/simulation/AnalysisSimulatorSlider.js +++ b/src/components/analysis/simulation/AnalysisSimulatorSlider.js @@ -8,21 +8,22 @@ const AnalysisSimulatorSlider = ({ setSliderCount, countArray }) => { - // hh:mm 형식으로 바꿔주는 코드 - function convertToTimeFormat(number) { - // 시간과 분 계산 - const hours = Math.floor(number / 60); - const minutes = Math.floor(number % 60); + const convertToTimeFormat = number => { + // 시간, 분, 초 계산 + const hours = Math.floor(number / 3600); + const minutes = Math.floor((number % 3600) / 60); + const seconds = Math.floor(number % 60); // 2자리 숫자로 포맷팅 const formattedHours = String(hours).padStart(2, '0'); const formattedMinutes = String(minutes).padStart(2, '0'); + const formattedSeconds = String(seconds).padStart(2, '0'); // 시간 문자열 생성 - const timeString = `${formattedHours}:${formattedMinutes}`; + const timeString = `${formattedHours}:${formattedMinutes}:${formattedSeconds}`; return timeString; - } + }; // 슬라이더 값이 바뀔 때마다 실행되는 함수 const colorOptions = { @@ -55,9 +56,10 @@ const AnalysisSimulatorSlider = ({ }, onChange: e => { function timeStringToMinutes(timeString) { - const [hours, minutes] = timeString.split(':').map(Number); - const totalMinutes = hours * 60 + minutes; - return totalMinutes.toString(); + const [hours, minutes, seconds] = timeString.split(':').map(Number); + const totalSeconds = hours * 3600 + minutes * 60 + seconds; + + return totalSeconds.toString(); } setSliderCount(e.map(timeStringToMinutes)); diff --git a/src/containers/analysis/simulator/AnalysisSimulationContainer.js b/src/containers/analysis/simulator/AnalysisSimulationContainer.js index 8befd73e..0160766a 100644 --- a/src/containers/analysis/simulator/AnalysisSimulationContainer.js +++ b/src/containers/analysis/simulator/AnalysisSimulationContainer.js @@ -1,5 +1,5 @@ import moment from 'moment'; -import { useEffect, useState, useCallback } from 'react'; +import { useEffect, useState, useCallback, useRef } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { AnalysisSimulationDetail } from '../../../components/analysis/simulation/AnalysisSimulationDetail'; import { AnalysisSimulationMenu } from '../../../components/analysis/simulation/AnalysisSimulationMenu'; @@ -61,6 +61,14 @@ export const AnalysisSimulationContainer = props => { minVal: 0 }); + // 재생 속도 배속 + const [speed, setSpeed] = useState(1000); + + const [currentSpeed, setCurrentSpeed] = useState(1000); + + // 타이머 Ref 전역 + const timerRef = useRef(null); + const dispatch = useDispatch(); // 드론 갯수 @@ -82,38 +90,49 @@ export const AnalysisSimulationContainer = props => { ); setCountArray(countCheck); - const timer = setInterval(() => { - if (playCount == log.length) { - playCount = 0; - clearInterval(timer); - setIsPlay(false); - } - setInfo({ ...log[playCount], playCount, playCounts }); - if (log[playCount]?.srvrRcvDt) { - setTimeCd(moment(log[playCount]?.srvrRcvDt).format('HH:mm')); - } + timer(isPlay, log); + + if (speed !== currentSpeed) { + clearInterval(timerRef.currnet); + setCurrentSpeed(speed); + } + return () => clearInterval(timerRef.current); + } + }, [isPlay, log, speed]); + + // 타이머 로직 함수 + const timer = (isPlay, log) => { + timerRef.current = setInterval(() => { + if (playCount == log.length) { + playCount = 0; + clearInterval(timerRef.current); + setIsPlay(false); + } + setInfo({ ...log[playCount], playCount, playCounts }); + if (log[playCount]?.srvrRcvDt) { + setTimeCd(moment(log[playCount]?.srvrRcvDt).format('HH:mm')); + } + + playCounts = moment(log[playCount]?.srvrRcvDt).diff( + moment(log[0]?.srvrRcvDt), + 'seconds' + ); - playCounts = moment(log[playCount]?.srvrRcvDt).diff( + setDronLength( + moment(log[log.length - 1]?.srvrRcvDt).diff( moment(log[0]?.srvrRcvDt), 'seconds' - ); - - setDronLength( - moment(log[log.length - 1]?.srvrRcvDt).diff( - moment(log[0]?.srvrRcvDt), - 'seconds' - ) - ); - playCount++; - }, 1000); - - return () => clearInterval(timer); - } - }, [isPlay, log]); + ) + ); + playCount++; + }, speed); + }; - // + // 새 리스트 선택시 초기화 useEffect(() => { if (isPlay) { + setSpeed(1000); + setCurrentSpeed(1000); setInfo({ ...log[playCount], playCount, playCounts }); setIsPlay(false); } @@ -165,23 +184,6 @@ export const AnalysisSimulationContainer = props => { if (log) { setInfo({ ...log[playCount], playCount: 0 }); } - - // let arrDate = log?.map(date => { - // const dateval = date.srvrRcvDt; - // if (dateval) { - // return Number(moment(dateval).format('DDHHmmss')); - // } else { - // return 0; - // } - // }); - // setSliderVal({ - // minVal: Math.min.apply(null, arrDate), - // maxVal: Math.max.apply(null, arrDate) - // }); - // let maxDate = log.map(date => { - // return Math.max(date.srvrRcvDt); - // }); - // let maxDate; }, [log]); // 검색 헨들러 @@ -305,6 +307,8 @@ export const AnalysisSimulationContainer = props => { setOpenReportList={handlerOpenReportList} dronLength={dronLength} countArray={countArray} + setSpeed={setSpeed} + speed={speed} />