'use client' import { useContext, useEffect, useRef } from 'react' import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil' import QContextMenu from '@/components/common/context-menu/QContextMenu' import PanelBatchStatistics from '@/components/floor-plan/modal/panelBatch/PanelBatchStatistics' import ImgLoad from '@/components/floor-plan/modal/ImgLoad' import { useCanvas } from '@/hooks/useCanvas' import { usePlan } from '@/hooks/usePlan' import { useContextMenu } from '@/hooks/useContextMenu' import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize' import { canvasZoomState, currentMenuState } from '@/store/canvasAtom' import { totalDisplaySelector } from '@/store/settingAtom' import { POLYGON_TYPE } from '@/common/common' import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider' import { QcastContext } from '@/app/QcastProvider' import { makersState, modelsState, moduleStatisticsState, pcsCheckState, selectedMakerState, selectedModelsState, seriesState, } from '@/store/circuitTrestleAtom' import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController' import { useCanvasSetting } from '@/hooks/option/useCanvasSetting' import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' import { useEvent } from '@/hooks/useEvent' import { compasDegAtom } from '@/store/orientationAtom' import { hotkeyStore } from '@/store/hotkeyAtom' import { usePopup } from '@/hooks/usePopup' import { outerLinePointsState } from '@/store/outerLineAtom' export default function CanvasFrame() { const canvasRef = useRef(null) const { canvas } = useCanvas('canvas') const { canvasLoadInit, gridInit } = useCanvasConfigInitialize() const { closeAll } = usePopup() const currentMenu = useRecoilValue(currentMenuState) const { floorPlanState } = useContext(FloorPlanContext) const { contextMenu, handleClick } = useContextMenu() const { plans, currentCanvasPlan, resetCanvasStatus } = usePlan() const totalDisplay = useRecoilValue(totalDisplaySelector) // 집계표 표시 여부 const { setIsGlobalLoading } = useContext(QcastContext) const resetModuleStatisticsState = useResetRecoilState(moduleStatisticsState) const resetOuterLinePoints = useResetRecoilState(outerLinePointsState) const resetMakersState = useResetRecoilState(makersState) const resetSelectedMakerState = useResetRecoilState(selectedMakerState) const resetSeriesState = useResetRecoilState(seriesState) const resetModelsState = useResetRecoilState(modelsState) const resetCompasDeg = useResetRecoilState(compasDegAtom) const [zoom, setCanvasZoom] = useRecoilState(canvasZoomState) const resetSelectedModelsState = useResetRecoilState(selectedModelsState) const resetPcsCheckState = useResetRecoilState(pcsCheckState) const { handleModuleSelectionTotal } = useCanvasPopupStatusController() const { basicSetting, fetchBasicSettings } = useCanvasSetting() const { selectedMenu, setSelectedMenu } = useCanvasMenu() const { initEvent } = useEvent() const loadCanvas = () => { if (!canvas) return canvas?.clear() // 캔버스를 초기화합니다. if (currentCanvasPlan) { const plan = plans.find((plan) => plan.id === currentCanvasPlan.id) if (plan?.canvasStatus && floorPlanState.objectNo === currentCanvasPlan.objectNo) { canvas?.loadFromJSON(JSON.parse(plan.canvasStatus), function () { canvasLoadInit() //config된 상태로 캔버스 객체를 그린다 canvas?.renderAll() // 캔버스를 다시 그립니다. if (canvas.viewportTransform) { if (canvas.viewportTransform[0] !== 1) { setCanvasZoom(Number((canvas.viewportTransform[0] * 100).toFixed(0))) } } canvas.originViewPortTransform = canvas.viewportTransform if (canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE).length > 0) { setTimeout(() => { setSelectedMenu('module') }, 500) } else if (canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL).length > 0) { setSelectedMenu('outline') } else { setTimeout(() => { setSelectedMenu('surface') }, 500) } const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) roofs.forEach((roof) => { const auxiliaryLines = canvas .getObjects() .filter((obj) => obj.name === 'auxiliaryLine' && roof.inPolygonImproved(obj.startPoint) && roof.inPolygonImproved(obj.endPoint)) auxiliaryLines.forEach((auxiliaryLine) => { roof.innerLines.push(auxiliaryLine) }) }) initEvent() }) } else { setSelectedMenu(null) } Object.keys(currentCanvasPlan).length > 0 && canvas && handleModuleSelectionTotal() } else { setSelectedMenu(null) } gridInit() } useEffect(() => { loadCanvas() resetRecoilData() /* 플랜번호가 있으면 베이직세팅 팝업 데이터 로드 */ if (currentCanvasPlan.planNo) { /* 약간의 지연을 줘서 roofMaterials가 로드될 시간을 확보 */ setTimeout(() => { fetchBasicSettings(Number(currentCanvasPlan.planNo), null) }, 100) } }, [currentCanvasPlan, canvas]) useEffect(() => { setIsGlobalLoading(false) // 혹시 모를 팝업이 떠있는 경우 닫고 시작한다. closeAll() return () => { canvas?.clear() resetCanvasStatus() } }, []) const resetRecoilData = () => { // resetModuleStatisticsState() resetOuterLinePoints() resetMakersState() resetSelectedMakerState() resetSeriesState() resetModelsState() resetCompasDeg() resetSelectedModelsState() resetPcsCheckState() } /** * 캔버스가 있을 경우 핫키 이벤트 처리 * hotkeyStore에 핫키 이벤트 리스너 추가 * * const hotkeys = [ { key: 'c', fn: () => asdf() }, { key: 'v', fn: () => qwer() }, ] setHotkeyStore(hotkeys) */ const hotkeyState = useRecoilValue(hotkeyStore) const hotkeyHandlerRef = useRef(null) useEffect(() => { hotkeyHandlerRef.current = (e) => { hotkeyState.forEach((hotkey) => { if (e.key === hotkey.key) { hotkey.fn() } }) } document.addEventListener('keyup', hotkeyHandlerRef.current) return () => { if (hotkeyHandlerRef.current) { document.removeEventListener('keyup', hotkeyHandlerRef.current) } } }, [hotkeyState]) /** 핫키 이벤트 처리 끝 */ return (