import { useRecoilValue } from 'recoil' import { canvasState, currentObjectState } from '@/store/canvasAtom' import { usePopup } from '@/hooks/usePopup' import { useMessage } from '@/hooks/useMessage' import { useEffect, useRef, useState } from 'react' import { useEvent } from '@/hooks/useEvent' import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import { getDegreeByChon } from '@/util/canvas-util' //동선이동 형 올림 내림 export function useMovementSetting(id) { const TYPE = { FLOW_LINE: 'flowLine', // 동선이동 UP_DOWN: 'updown', //형 올림내림 } const canvas = useRecoilValue(canvasState) const { initEvent, addCanvasMouseEventListener } = useEvent() // const { initEvent, addCanvasMouseEventListener } = useContext(EventContext) const { closePopup } = usePopup() const { getMessage } = useMessage() const currentObject = useRecoilValue(currentObjectState) const selectedObject = useRef(null) const buttonType = [ { id: 1, name: getMessage('modal.movement.flow.line.move'), type: TYPE.FLOW_LINE }, { id: 2, name: getMessage('modal.movement.flow.line.updown'), type: TYPE.UP_DOWN }, ] const [type, setType] = useState(TYPE.FLOW_LINE) const typeRef = useRef(type) const FLOW_LINE_REF = { POINTER_INPUT_REF: useRef(null), FILLED_INPUT_REF: useRef(null), DOWN_LEFT_RADIO_REF: useRef(null), UP_RIGHT_RADIO_REF: useRef(null), } const UP_DOWN_REF = { UP_INPUT_REF: useRef(null), DOWN_INPUT_REF: useRef(null), UP_RADIO_REF: useRef(null), DOWN_RADIO_REF: useRef(null), } useEffect(() => { typeRef.current = type canvas.getObjects().forEach((obj) => { obj.set({ selectable: false }) }) const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) // 기존 wallLine의 visible false roofs.forEach((roof) => { roof.set({ selectable: false }) roof.set({ strokeWidth: 1 }) roof.set({ stroke: '#000000' }) roof.innerLines.forEach((line) => { line.bringToFront() line.set({ selectable: false }) line.set({ strokeWidth: 1 }) line.set({ stroke: '#000000' }) }) roof.separatePolygon?.forEach((polygon) => { polygon.bringToFront() polygon.set({ selectable: false }) polygon.set({ strokeWidth: 1 }) polygon.set({ stroke: '#000000' }) }) }) if (type === TYPE.FLOW_LINE) { roofs.forEach((roof) => { roof.innerLines.forEach((line) => { if (line.name === LINE_TYPE.SUBLINE.RIDGE) { line.bringToFront() line.set({ selectable: true }) line.set({ strokeWidth: 4 }) line.set({ stroke: '#1083E3' }) } }) }) } else if (type === TYPE.UP_DOWN) { const wallLine = canvas.getObjects().filter((obj) => obj.name === 'wallLine') // 기존 outerLine의 selectable true wallLine.forEach((line) => { line.bringToFront() line.set({ selectable: true }) }) } canvas.renderAll() }, [type]) useEffect(() => { canvas.renderAll() addCanvasMouseEventListener('mouse:move', mouseMoveEvent) addCanvasMouseEventListener('mouse:down', mouseDownEvent) return () => { initEvent() const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) wallLines.forEach((line) => { line.set({ visible: true }) }) const wallLine = canvas.getObjects().filter((obj) => obj.name === 'wallLine') // 기존 outerLine의 selectable true wallLine.forEach((line) => { let wallStroke, wallStrokeWidth switch (line.attributes.type) { case LINE_TYPE.WALLLINE.EAVES: wallStroke = '#45CD7D' wallStrokeWidth = 4 break case LINE_TYPE.WALLLINE.HIPANDGABLE: wallStroke = '#45CD7D' wallStrokeWidth = 4 break case LINE_TYPE.WALLLINE.GABLE: wallStroke = '#3FBAE6' wallStrokeWidth = 4 break case LINE_TYPE.WALLLINE.JERKINHEAD: wallStroke = '#3FBAE6' wallStrokeWidth = 4 break case LINE_TYPE.WALLLINE.SHED: wallStroke = '#000000' wallStrokeWidth = 4 break case LINE_TYPE.WALLLINE.WALL: wallStroke = '#000000' wallStrokeWidth = 4 break } line.set({ selectable: false, stroke: wallStroke, strokeWidth: wallStrokeWidth }) }) canvas.renderAll() } }, []) useEffect(() => { selectedObject.current = null if (!currentObject) { return } clearRef() selectedObject.current = currentObject if (currentObject.name === 'wallLine') { currentObject.set({ stroke: '#EA10AC' }) currentObject.bringToFront() } canvas.renderAll() }, [currentObject]) const clearRef = () => { if (type === TYPE.FLOW_LINE) { FLOW_LINE_REF.FILLED_INPUT_REF.current.value = '' FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = true FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked = false } if (type === TYPE.UP_DOWN) { UP_DOWN_REF.UP_INPUT_REF.current.value = '' UP_DOWN_REF.DOWN_INPUT_REF.current.value = '' UP_DOWN_REF.UP_RADIO_REF.current.checked = true UP_DOWN_REF.DOWN_RADIO_REF.current.checked = false } } const mouseDownEvent = (e) => { if (typeRef.current === TYPE.FLOW_LINE) { saveFlowLine(e) } else { updownDownEvent(e) } } const mouseMoveEvent = (e) => { if (typeRef.current === TYPE.FLOW_LINE) { flowLineMoveEvent(e) } else { updownMoveEvent(e) } } //동선 이동 마우스 클릭 이벤트 const saveFlowLine = (e) => { const target = selectedObject.current if (!target) { return } let newPoint = [] if (Math.sign(target.x1 - target.x2) !== 0) { newPoint = [ target.x1, target.y1 - Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10), target.x2, target.y2 - Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10), ] } else { newPoint = [ target.x1 + Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10), target.y1, target.x2 + Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10), target.y2, ] } clearRef() const cloned = new fabric.Line(newPoint, {}) let currentObject = selectedObject.current const currentX1 = currentObject.x1, currentY1 = currentObject.y1, currentX2 = currentObject.x2, currentY2 = currentObject.y2 const roof = canvas.getObjects().find((obj) => obj.id === currentObject.attributes.roofId) if (roof.separatePolygon.length > 0) { const separatePolygon = roof.separatePolygon separatePolygon .filter((polygon) => polygon.points.some((point) => (point.x === currentX1 && point.y === currentY1) || (point.x === currentX2 && point.y === currentY2)), ) .forEach((polygon) => { const newPoints = polygon.points.map((point) => { if (point.x === currentX1 && point.y === currentY1) { return { x: newPoint[0], y: newPoint[1] } } else if (point.x === currentX2 && point.y === currentY2) { return { x: newPoint[2], y: newPoint[3] } } else { return point } }) polygon.set({ points: newPoints }) polygon.setCoords() polygon.addLengthText() polygon.initLines() const slope = (line) => (line.x2 - line.x1 === 0 ? Infinity : (line.y2 - line.y1) / (line.x2 - line.x1)) const currentDegree = polygon.attributes.pitch > 0 ? getDegreeByChon(polygon.attributes.pitch) : polygon.attributes.degree polygon.lines.forEach((line) => { line.attributes.planeSize = Math.round(Math.sqrt(Math.pow(line.x2 - line.x1, 2) + Math.pow(line.y2 - line.y1, 2)) * 10) if (currentDegree > 0 && slope(line) !== slope(currentObject)) { const height = Math.tan(currentDegree * (Math.PI / 180)) * line.attributes.planeSize line.attributes.actualSize = Math.round(Math.sqrt(Math.pow(line.attributes.planeSize, 2) + Math.pow(height, 2))) } else { line.attributes.actualSize = line.attributes.planeSize } }) }) } else { roof.innerLines .filter((line) => currentObject !== line) .filter( (line) => (line.x1 === currentX1 && line.y1 === currentY1) || (line.x2 === currentX1 && line.y2 === currentY1) || (line.x1 === currentX2 && line.y1 === currentY2) || (line.x2 === currentX2 && line.y2 === currentY2), ) .forEach((line) => { const lineDegree = 90 - Math.asin(line.attributes.planeSize / line.attributes.actualSize) * (180 / Math.PI) if (line.x1 === currentX1 && line.y1 === currentY1) { line.set({ x1: newPoint[0], y1: newPoint[1] }) } else if (line.x2 === currentX1 && line.y2 === currentY1) { line.set({ x2: newPoint[0], y2: newPoint[1] }) } else if (line.x1 === currentX2 && line.y1 === currentY2) { line.set({ x1: newPoint[2], y1: newPoint[3] }) } else if (line.x2 === currentX2 && line.y2 === currentY2) { line.set({ x2: newPoint[2], y2: newPoint[3] }) } line.setCoords() line.attributes.planeSize = Math.round(Math.sqrt(Math.pow(line.x2 - line.x1, 2) + Math.pow(line.y2 - line.y1, 2)) * 10) line.attributes.actualSize = Math.round( Math.sqrt(Math.pow(line.attributes.planeSize, 2) + Math.pow(line.attributes.planeSize * Math.tan(lineDegree * (Math.PI / 180)), 2)), ) }) } currentObject.set({ x1: cloned.x1, y1: cloned.y1, x2: cloned.x2, y2: cloned.y2 }) currentObject.setCoords() canvas.renderAll() canvas.discardActiveObject() } //형 올림내림 마우스 클릭 이벤트 const updownDownEvent = (e) => { console.log('updownDownEvent') } const flowLineMoveEvent = (e) => { const target = canvas.getActiveObject() if (!target) { return } const { top: targetTop, left: targetLeft } = target const currentX = canvas.getPointer(e.e).x const currentY = Math.floor(canvas.getPointer(e.e).y) if (Math.sign(target.x1 - target.x2) !== 0) { if (targetTop > currentY) { FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked = true FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.round(targetTop - currentY)) / 10000).toFixed(5) * 100000) } else { FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = true FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.round(targetTop - currentY)) / 10000).toFixed(5) * 100000) } } else { if (targetLeft > currentX) { FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked = true FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.round(currentX - targetLeft)) / 10000).toFixed(5) * 100000) } else { FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = true FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.round(currentX - targetLeft)) / 10000).toFixed(5) * 100000) } } canvas?.renderAll() } const updownMoveEvent = (e) => { const target = canvas.getActiveObject() if (!target) { return } const direction = target.direction const { top: targetTop, left: targetLeft } = target const currentX = canvas.getPointer(e.e).x const currentY = Math.floor(canvas.getPointer(e.e).y) if (direction === 'left' || direction === 'right') { if (targetTop > currentY) { UP_DOWN_REF.DOWN_RADIO_REF.current.checked = true UP_DOWN_REF.UP_INPUT_REF.current.value = '' UP_DOWN_REF.DOWN_INPUT_REF.current.value = Math.floor((Number(Math.abs(targetTop - currentY)) / 10000).toFixed(5) * 100000) } else { UP_DOWN_REF.UP_RADIO_REF.current.checked = true UP_DOWN_REF.DOWN_INPUT_REF.current.value = '' UP_DOWN_REF.UP_INPUT_REF.current.value = Math.floor((Number(Math.abs(targetTop - currentY)) / 10000).toFixed(5) * 100000) } } else { if (targetLeft > currentX) { UP_DOWN_REF.DOWN_RADIO_REF.current.checked = true UP_DOWN_REF.UP_INPUT_REF.current.value = '' UP_DOWN_REF.DOWN_INPUT_REF.current.value = Math.floor((Number(Math.abs(targetLeft - currentX)) / 10000).toFixed(5) * 100000) } else { UP_DOWN_REF.UP_RADIO_REF.current.checked = true UP_DOWN_REF.DOWN_INPUT_REF.current.value = '' UP_DOWN_REF.UP_INPUT_REF.current.value = Math.floor((Number(Math.abs(targetLeft - currentX)) / 10000).toFixed(5) * 100000) } } canvas?.renderAll() } const handleSave = () => { if (type === TYPE.FLOW_LINE) { saveFlowLine() } else { // 형 올림내림 if (UP_DOWN_REF.UP_RADIO_REF.current.checked) { // 자릿수를 올리다 체크 const length = Number(UP_DOWN_REF.UP_INPUT_REF.current.value) } else { // 자릿수를 내리다 체크 const length = Number(UP_DOWN_REF.DOWN_INPUT_REF.current.value) } } } return { TYPE, closePopup, buttonType, type, setType, FLOW_LINE_REF, UP_DOWN_REF, handleSave, } }