import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import { canvasState, currentMenuState, currentObjectState } from '@/store/canvasAtom' import { useEffect, useRef, useState } from 'react' import { useSwal } from '@/hooks/useSwal' import { usePolygon } from '@/hooks/usePolygon' import { basicSettingState, roofDisplaySelector, roofMaterialsSelector, selectedRoofMaterialSelector } from '@/store/settingAtom' import { usePopup } from '@/hooks/usePopup' import { POLYGON_TYPE } from '@/common/common' import { v4 as uuidv4 } from 'uuid' import ActualSizeSetting from '@/components/floor-plan/modal/roofAllocation/ActualSizeSetting' import { useMessage } from '@/hooks/useMessage' import useMenu from '@/hooks/common/useMenu' import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' import { menuTypeState } from '@/store/menuAtom' import { useRoofFn } from '@/hooks/common/useRoofFn' // 지붕면 할당 export function useRoofAllocationSetting(id) { const canvas = useRecoilValue(canvasState) const roofDisplay = useRecoilValue(roofDisplaySelector) const { drawDirectionArrow, addLengthText, splitPolygonWithLines, splitPolygonWithSeparate } = usePolygon() const [popupId, setPopupId] = useState(uuidv4()) const { addPopup, closePopup, closeAll } = usePopup() const { getMessage } = useMessage() const currentObject = useRecoilValue(currentObjectState) const { swalFire } = useSwal() const { setMenuNumber } = useCanvasMenu() const setMenuType = useSetRecoilState(menuTypeState) const roofMaterials = useRecoilValue(roofMaterialsSelector) const selectedRoofMaterial = useRecoilValue(selectedRoofMaterialSelector) const [basicSetting, setBasicSetting] = useRecoilState(basicSettingState) const [currentRoofMaterial, setCurrentRoofMaterial] = useState(roofMaterials[0]) // 팝업 내 기준 지붕재 const [roofList, setRoofList] = useState(basicSetting.roofs) // 배치면 초기설정에서 선택한 지붕재 배열 const [editingLines, setEditingLines] = useState([]) const isFirstRef = useRef(0) const { setSurfaceShapePattern } = useRoofFn() useEffect(() => { const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) // roofPolygon.innerLines roofBases.forEach((roof) => { roof.innerLines.forEach((line) => { if (!line.attributes.actualSize || line.attributes?.actualSize === 0) { line.set({ strokeWidth: 4, stroke: 'black', selectable: true, }) } if (editingLines.includes(line)) { line.set({ strokeWidth: 2, stroke: 'black', selectable: true, }) } }) }) if (currentObject && currentObject.name && ['auxiliaryLine', 'ridge', 'hip'].includes(currentObject.name)) { currentObject.set({ strokeWidth: 4, stroke: '#EA10AC', }) } }, [currentObject]) useEffect(() => { // canvas.getObjects().filter((obj) => obj.type === 'QLine') const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) if (roofBases.length === 0) { swalFire({ text: '할당할 지붕이 없습니다.' }) closePopup(id) } }, []) const onAddRoofMaterial = () => { if (roofList.length >= 4) { swalFire({ type: 'alert', icon: 'error', text: getMessage('지붕재는 4개까지 선택 가능합니다.') }) return } setRoofList([...roofList, { ...currentRoofMaterial, selected: false, id: currentRoofMaterial.roofMatlCd, name: currentRoofMaterial.roofMatlNm }]) } const onDeleteRoofMaterial = (idx) => { setRoofList([...roofList.filter((_, index) => index !== idx)]) } const { handleMenu } = useMenu() const [currentMenu, setCurrentMenu] = useRecoilState(currentMenuState) // 선택한 지붕재로 할당 const handleSave = () => { // 모두 actualSize 있으면 바로 적용 없으면 actualSize 설정 if (checkInnerLines()) { addPopup(popupId, 1, ) } else { apply() } } // 지붕재 오른쪽 마우스 클릭 후 단일로 지붕재 변경 필요한 경우 const handleSaveContext = () => { const selectedRoofMaterial = roofList.find((roof) => roof.selected) setSurfaceShapePattern(currentObject, roofDisplay.column, false, selectedRoofMaterial) closeAll() } const handleAlloc = () => { if (!checkInnerLines()) { apply() } else { swalFire({ type: 'alert', icon: 'error', text: getMessage('실제치수를 입력해 주세요.'), }) } } const checkInnerLines = () => { const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) // roofPolygon.innerLines let result = false roofBases.forEach((roof) => { roof.innerLines.forEach((line) => { if (!line.attributes.actualSize || line.attributes?.actualSize === 0) { line.set({ strokeWidth: 4, stroke: 'black', selectable: true, }) result = true } }) }) if (result) canvas?.renderAll() return result } const apply = () => { const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF && !obj.isFixed) const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) roofBases.forEach((roofBase) => { try { if (roofBase.separatePolygon.length > 0) { splitPolygonWithSeparate(roofBase.separatePolygon) } else { splitPolygonWithLines(roofBase) } } catch (e) { return } roofBase.innerLines.forEach((line) => { canvas.remove(line) }) canvas.remove(roofBase) }) wallLines.forEach((wallLine) => { canvas.remove(wallLine) }) setBasicSetting((prev) => { return { ...prev, roofs: roofList, selectedRoofMaterial: roofList.find((roof) => roof.selected), } }) const roofs = canvas.getObjects().filter((obj) => obj.name === 'roof') roofs.forEach((roof) => { if (roof.isFixed) return roof.set({ isFixed: true, }) setSurfaceShapePattern(roof, roofDisplay.column) drawDirectionArrow(roof) }) const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'outerLinePoint' || obj.name === 'outerLine') removeTargets.forEach((obj) => { canvas.remove(obj) }) setEditingLines([]) closeAll() setMenuNumber(3) setMenuType('surface') } const setLineSize = (id, size) => { const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) roofBases.forEach((roof) => { roof.innerLines.forEach((line) => { if (id === line.id) { setEditingLines([...editingLines.filter((editLine) => editLine.id !== line.id), line]) line.attributes.actualSize = size line.set({ strokeWidth: 2, stroke: 'black', }) } }) }) canvas?.renderAll() } // 지붕재 변경 const handleChangeRoofMaterial = (value, index) => { if (isFirstRef.current === 0) { isFirstRef.current++ return } const selectedRoofMaterial = roofMaterials.find((roof) => roof.roofMatlCd === value.id) const newRoofList = roofList.map((roof, idx) => { if (idx === index) { return { ...selectedRoofMaterial } } return roof }) setRoofList(newRoofList) } // 기본 지붕재 radio값 변경 const handleDefaultRoofMaterial = (index) => { const newRoofList = roofList.map((roof, idx) => { return { ...roof, selected: idx === index } }) setRoofList(newRoofList) } // 서까래 변경 const handleChangeRaft = (e, index) => { const raftValue = e.value const newRoofList = roofList.map((roof, idx) => { if (idx === index) { return { ...roof, raft: raftValue } } return roof }) setRoofList(newRoofList) } const handleChangeLayout = (layoutValue, index) => { const newRoofList = roofList.map((roof, idx) => { if (idx === index) { return { ...roof, layout: layoutValue } } return roof }) setRoofList(newRoofList) } return { handleSave, onAddRoofMaterial, onDeleteRoofMaterial, handleAlloc, setLineSize, roofMaterials, selectedRoofMaterial, basicSetting, setBasicSetting, currentRoofMaterial, setCurrentRoofMaterial, roofList, handleDefaultRoofMaterial, handleChangeRoofMaterial, handleChangeRaft, handleChangeLayout, handleSaveContext, } }