'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 { currentMenuState } from '@/store/canvasAtom' import { roofMaterialsAtom, totalDisplaySelector } from '@/store/settingAtom' import { MENU, 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 { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' import { useMasterController } from '@/hooks/common/useMasterController' import { hotkeyStore } from '@/store/hotkeyAtom' import { usePopup } from '@/hooks/usePopup' export default function CanvasFrame() { const [roofMaterials, setRoofMaterials] = useRecoilState(roofMaterialsAtom) const { getRoofMaterialList } = useMasterController() useEffect(() => { async function initRoofMaterial() { if (roofMaterials.length !== 0) { return } const { data } = await getRoofMaterialList() const roofLists = data.map((item, idx) => ({ ...item, id: item.roofMatlCd, name: item.roofMatlNm, selected: idx === 0, index: idx, nameJp: item.roofMatlNmJp, length: item.lenBase && parseInt(item.lenBase), width: item.widBase && parseInt(item.widBase), raft: item.raftBase && parseInt(item.raftBase), layout: ['ROOF_ID_SLATE', 'ROOF_ID_SINGLE'].includes(item.roofMatlCd) ? ROOF_MATERIAL_LAYOUT.STAIRS : ROOF_MATERIAL_LAYOUT.PARALLEL, hajebichi: item.roofPchBase && parseInt(item.roofPchBase), pitch: item.pitch ? parseInt(item.pitch) : 4, angle: item.angle ? parseInt(item.angle) : 21.8, })) setRoofMaterials(roofLists) } initRoofMaterial() }, []) 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 resetMakersState = useResetRecoilState(makersState) const resetSelectedMakerState = useResetRecoilState(selectedMakerState) const resetSeriesState = useResetRecoilState(seriesState) const resetModelsState = useResetRecoilState(modelsState) const resetCompasDeg = useResetRecoilState(compasDegAtom) 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.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE).length > 0) { setSelectedMenu('module') } else { setSelectedMenu('surface') } initEvent() }) } Object.keys(currentCanvasPlan).length > 0 && canvas && handleModuleSelectionTotal() } 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() 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 (