'use client' import { useMessage } from '@/hooks/useMessage' import { useRecoilState, useRecoilValue } from 'recoil' import { canvasState } from '@/store/canvasAtom' import { INPUT_TYPE, BATCH_TYPE } from '@/common/common' import { useEvent } from '@/hooks/useEvent' import { polygonToTurfPolygon, rectToPolygon, pointsToTurfPolygon } from '@/util/canvas-util' import { useSwal } from '@/hooks/useSwal' import * as turf from '@turf/turf' export function useObjectBatch() { const { getMessage } = useMessage() const canvas = useRecoilValue(canvasState) const { addCanvasMouseEventListener, initEvent } = useEvent() const { swalFire } = useSwal() const applyOpeningAndShadow = (objectPlacement, buttonAct, surfaceShapePolygons, setShowObjectSettingModal) => { const selectedType = objectPlacement.typeRef.current.find((radio) => radio.checked).value const isCrossChecked = buttonAct === 1 ? objectPlacement.isCrossRef.current.checked : false const objTempName = buttonAct === 1 ? BATCH_TYPE.OPENING_TEMP : BATCH_TYPE.SHADOW_TEMP const objName = buttonAct === 1 ? BATCH_TYPE.OPENING : BATCH_TYPE.SHADOW let rect, isDown, origX, origY let selectedSurface //프리입력 if (selectedType === INPUT_TYPE.FREE) { addCanvasMouseEventListener('mouse:down', (e) => { isDown = true const pointer = canvas.getPointer(e.e) surfaceShapePolygons.forEach((surface) => { if (surface.inPolygon({ x: pointer.x, y: pointer.y })) { selectedSurface = surface } }) if (!selectedSurface) { swalFire({ text: '지붕안에 그려야해요', icon: 'error' }) initEvent() //이벤트 초기화 return } origX = pointer.x origY = pointer.y rect = new fabric.Rect({ left: origX, top: origY, originX: 'left', originY: 'top', width: 0, height: 0, angle: 0, stroke: 'black', }) //개구냐 그림자냐에 따라 변경 rect.set({ fill: buttonAct === 1 ? 'white' : 'rgba(0, 0, 0, 0.4)', name: objTempName, }) canvas?.add(rect) }) addCanvasMouseEventListener('mouse:move', (e) => { if (!isDown) return if (selectedSurface) { const pointer = canvas.getPointer(e.e) const width = pointer.x - origX const height = pointer.y - origY rect.set({ width: Math.abs(width), height: Math.abs(height) }) if (width < 0) { rect.set({ left: Math.abs(pointer.x) }) } if (height < 0) { rect.set({ top: Math.abs(pointer.y) }) } canvas?.renderAll() } }) addCanvasMouseEventListener('mouse:up', (e) => { if (rect) { const rectPolygon = pointsToTurfPolygon(rectToPolygon(rect)) const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface) //지붕 밖으로 그렸을때 if (!turf.booleanWithin(rectPolygon, selectedSurfacePolygon)) { swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' }) //일단 지워 deleteTempObjects(setShowObjectSettingModal) return } if (!isCrossChecked) { const preObjects = canvas?.getObjects().filter((obj) => obj.name === BATCH_TYPE.OPENING || obj.name === BATCH_TYPE.SHADOW) const preObjectsArray = preObjects.map((obj) => rectToPolygon(obj)) const isCross = preObjectsArray.some((object) => turf.booleanOverlap(pointsToTurfPolygon(object), rectPolygon)) if (isCross) { swalFire({ text: '겹치기 불가요...', icon: 'error' }) deleteTempObjects(setShowObjectSettingModal) return } } isDown = false rect.set({ name: objName }) rect.setCoords() initEvent() } }) } else if (selectedType === INPUT_TYPE.DIMENSION) { const width = objectPlacement.widthRef.current.value / 10 const height = objectPlacement.heightRef.current.value / 10 if (width === '' || height === '' || width <= 0 || height <= 0) { swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' }) return } // setShowObjectSettingModal(false) //메뉴보이고 addCanvasMouseEventListener('mouse:move', (e) => { isDown = true if (!isDown) return canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === objTempName)) //움직일때 일단 지워가면서 움직임 const pointer = canvas.getPointer(e.e) surfaceShapePolygons.forEach((surface) => { if (surface.inPolygon({ x: pointer.x, y: pointer.y })) { selectedSurface = surface } }) rect = new fabric.Rect({ fill: 'white', stroke: 'black', strokeWidth: 1, width: width, height: height, left: pointer.x - width / 2, top: pointer.y - height / 2, selectable: true, lockMovementX: true, lockMovementY: true, lockRotation: true, lockScalingX: true, lockScalingY: true, }) //개구냐 그림자냐에 따라 변경 rect.set({ fill: buttonAct === 1 ? 'white' : 'rgba(0, 0, 0, 0.4)', name: objTempName, }) canvas?.add(rect) }) addCanvasMouseEventListener('mouse:up', (e) => { if (rect) { const rectPolygon = pointsToTurfPolygon(rectToPolygon(rect)) const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface) //지붕 밖으로 그렸을때 if (!turf.booleanWithin(rectPolygon, selectedSurfacePolygon)) { swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' }) //일단 지워 deleteTempObjects(setShowObjectSettingModal) return } if (!isCrossChecked) { const preObjects = canvas?.getObjects().filter((obj) => obj.name === BATCH_TYPE.OPENING || obj.name === BATCH_TYPE.SHADOW) const preObjectsArray = preObjects.map((obj) => rectToPolygon(obj)) const isCross = preObjectsArray.some((object) => turf.booleanOverlap(pointsToTurfPolygon(object), rectPolygon)) if (isCross) { swalFire({ text: '겹치기 불가요...', icon: 'error' }) deleteTempObjects(setShowObjectSettingModal) return } } isDown = false rect.set({ name: objName }) rect.setCoords() initEvent() } }) } } const deleteTempObjects = (setShowObjectSettingModal) => { const deleteTarget = canvas?.getObjects().filter((obj) => obj.name === BATCH_TYPE.OPENING_TEMP || obj.name === BATCH_TYPE.SHADOW_TEMP) canvas?.remove(...deleteTarget) initEvent() //이벤트 초기화 } return { applyOpeningAndShadow, } }