qcast-front/src/hooks/roofcover/useWallLineOffsetSetting.js
2025-03-19 13:28:20 +09:00

530 lines
18 KiB
JavaScript

import { canvasState, currentObjectState } from '@/store/canvasAtom'
import { useRecoilValue } from 'recoil'
import { useEffect, useRef, useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { useEvent } from '@/hooks/useEvent'
import { useLine } from '@/hooks/useLine'
import { useSwal } from '@/hooks/useSwal'
import { usePopup } from '@/hooks/usePopup'
// 외벽선 편집 및 오프셋
export function useWallLineOffsetSetting(id) {
const canvas = useRecoilValue(canvasState)
const { showLine, addLine } = useLine()
const { getMessage } = useMessage()
const { closePopup } = usePopup()
const { swalFire } = useSwal()
const { addCanvasMouseEventListener, initEvent } = useEvent()
// const { addCanvasMouseEventListener, initEvent } = useContext(EventContext)
const wallLineEditRef = useRef(null)
const length1Ref = useRef(null)
const length2Ref = useRef(null)
const radioTypeRef = useRef('1')
const currentWallLineRef = useRef(null)
const arrow1Ref = useRef(null)
const arrow2Ref = useRef(null)
const currentObject = useRecoilValue(currentObjectState)
const [isLoading, setIsLoading] = useState(false)
const drawLine = (point1, point2, idx, direction = currentWallLineRef.current.direction) => {
const line = addLine([point1.x, point1.y, point2.x, point2.y], {
stroke: 'black',
strokeWidth: 4,
idx: idx,
selectable: true,
name: 'outerLine',
x1: point1.x,
y1: point1.y,
x2: point2.x,
y2: point2.y,
direction: direction,
})
line.attributes = { ...currentWallLineRef.current.attributes }
}
const TYPES = {
WALL_LINE_EDIT: 'wallLineEdit',
OFFSET: 'offset',
}
const buttonMenu = [
{ id: 1, name: getMessage('modal.wallline.offset.setting.wallline.edit'), type: TYPES.WALL_LINE_EDIT },
{ id: 2, name: getMessage('modal.wallline.offset.setting.offset'), type: TYPES.OFFSET },
]
const [type, setType] = useState(TYPES.WALL_LINE_EDIT)
useEffect(() => {
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
if (outerLines.length === 0) {
swalFire({ text: getMessage('wall.line.not.found') })
closePopup(id)
return
}
outerLines.forEach((outerLine) => {
outerLine.set({ selectable: true })
showLine(outerLine)
})
//outerLine과 그 text만 남겨둔다.
const exceptObjs = canvas.getObjects().filter((obj) => obj.name !== 'outerLine' && obj.parent?.name !== 'outerLine')
exceptObjs.forEach((obj) => {
canvas.remove(obj)
})
canvas.setActiveObject(outerLines[0])
currentWallLineRef.current = outerLines[0]
addCircleByLine(currentWallLineRef.current)
addCanvasMouseEventListener('mouse:down', mouseDown)
setIsLoading(true)
return () => {
removeOuterLineEditCircle()
canvas.discardActiveObject()
initEvent()
}
}, [])
useEffect(() => {
if (!isLoading) {
return
}
canvas?.discardActiveObject()
removeOuterLineEditCircle()
addCanvasMouseEventListener('mouse:down', mouseDown)
if (type === TYPES.WALL_LINE_EDIT) {
addCircleByLine(currentWallLineRef.current)
}
}, [type])
useEffect(() => {
canvas
.getObjects()
.filter((obj) => obj.name === 'outerLine')
.forEach((line) => {
line.set({ stroke: 'black' })
})
if (currentObject?.name === 'outerLine') {
currentObject.set({ stroke: '#EA10AC' })
canvas.renderAll()
}
}, [currentObject])
const removeOuterLineEditCircle = () => {
canvas.remove(...canvas.getObjects().filter((obj) => obj.name === 'outerLineEditCircleStart' || obj.name === 'outerLineEditCircleEnd'))
}
const mouseDown = (e) => {
removeOuterLineEditCircle()
if (!e.target || (e.target && e.target.name !== 'outerLine')) {
currentWallLineRef.current = null
return
}
currentWallLineRef.current = e.target
if (type === TYPES.WALL_LINE_EDIT) {
addCircleByLine(currentWallLineRef.current)
}
}
const addCircleByLine = (line) => {
const direction = currentWallLineRef.current?.direction
let startPoint
let endPoint
let circle1, circle2
if (direction === 'top' || direction === 'bottom') {
// y1, y2중에 더 작은 값이 startPoint, 더 큰 값이 endPoint
if (line.y1 > line.y2) {
startPoint = { x: line.x2, y: line.y2 }
endPoint = { x: line.x1, y: line.y1 }
} else {
startPoint = { x: line.x1, y: line.y1 }
endPoint = { x: line.x2, y: line.y2 }
}
arrow1Ref.current = 'down'
arrow2Ref.current = 'up'
} else {
// x1, x2중에 더 작은 값이 startPoint, 더 큰 값이 endPoint
if (line.x1 > line.x2) {
startPoint = { x: line.x2, y: line.y2 }
endPoint = { x: line.x1, y: line.y1 }
} else {
startPoint = { x: line.x1, y: line.y1 }
endPoint = { x: line.x2, y: line.y2 }
}
arrow1Ref.current = 'right'
arrow2Ref.current = 'left'
}
circle1 = new fabric.Circle({
radius: 10,
fill: 'red',
top: startPoint.y - 10,
left: startPoint.x - 10,
name: 'outerLineEditCircleStart',
hasControls: false,
hasBorders: false,
lockMovementX: true,
lockMovementY: true,
})
circle2 = new fabric.Circle({
radius: 10,
fill: 'blue',
top: endPoint.y - 10,
left: endPoint.x - 10,
name: 'outerLineEditCircleEnd',
hasControls: false,
hasBorders: false,
lockMovementX: true,
lockMovementY: true,
})
wallLineEditRef.current.setArrow()
canvas.add(circle1)
canvas.add(circle2)
}
const handleSave = () => {
if (currentWallLineRef.current === null) {
// alert('보조선을 먼저 선택하세요')
return
}
switch (type) {
case TYPES.WALL_LINE_EDIT:
handleWallLineEditSave()
break
case TYPES.OFFSET:
handleOffsetSave()
break
}
}
const handleWallLineEditSave = () => {
const startPoint = canvas
.getObjects()
.filter((obj) => obj.name === 'outerLineEditCircleStart')
.map((obj) => {
return {
x: obj.left + obj.radius,
y: obj.top + obj.radius,
}
})[0]
const endPoint = canvas
.getObjects()
.filter((obj) => obj.name === 'outerLineEditCircleEnd')
.map((obj) => {
return {
x: obj.left + obj.radius,
y: obj.top + obj.radius,
}
})[0]
const length = Number(length1Ref.current.value) / 10
const length2 = Number(length2Ref.current.value) / 10
const currentIdx = currentWallLineRef.current.idx
const currentDirection = currentWallLineRef.current.direction
let point1, point2, point3
if (radioTypeRef.current === '1') {
// 1지점 선택시 방향은 down, right만 가능
if (arrow1Ref.current === 'down') {
if (currentDirection === 'top') {
point1 = { x: endPoint.x, y: endPoint.y }
point2 = { x: startPoint.x, y: startPoint.y + length }
point3 = { x: startPoint.x, y: startPoint.y }
} else {
point1 = { x: startPoint.x, y: startPoint.y }
point2 = { x: startPoint.x, y: startPoint.y + length }
point3 = { x: endPoint.x, y: endPoint.y }
}
} else {
if (currentDirection === 'left') {
point1 = { x: endPoint.x, y: endPoint.y }
point2 = { x: startPoint.x + length, y: startPoint.y }
point3 = { x: startPoint.x, y: startPoint.y }
} else {
point1 = { x: startPoint.x, y: startPoint.y }
point2 = { x: startPoint.x + length, y: startPoint.y }
point3 = { x: endPoint.x, y: endPoint.y }
}
}
} else {
// 2지점일 경우 방향은 up, left만 가능
if (arrow2Ref.current === 'up') {
if (currentDirection === 'bottom') {
point1 = { x: startPoint.x, y: startPoint.y }
point2 = { x: endPoint.x, y: endPoint.y - length2 }
point3 = { x: endPoint.x, y: endPoint.y }
} else {
point1 = { x: endPoint.x, y: endPoint.y }
point2 = { x: endPoint.x, y: endPoint.y - length2 }
point3 = { x: startPoint.x, y: startPoint.y }
}
} else {
if (currentDirection === 'right') {
point1 = { x: startPoint.x, y: startPoint.y }
point2 = { x: endPoint.x - length2, y: endPoint.y }
point3 = { x: endPoint.x, y: endPoint.y }
} else {
point1 = { x: endPoint.x, y: endPoint.y }
point2 = { x: endPoint.x - length2, y: endPoint.y }
point3 = { x: startPoint.x, y: startPoint.y }
}
}
}
rearrangeOuterLine(currentIdx + 1)
drawLine(point1, point2, currentIdx)
drawLine(point2, point3, currentIdx + 1)
removeOuterLineEditCircle()
canvas.remove(currentWallLineRef.current)
currentWallLineRef.current = null
canvas.renderAll()
}
const rearrangeOuterLine = (idxParam) => {
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
outerLines.forEach((outerLine) => {
if (outerLine.idx >= idxParam) {
outerLine.idx = outerLine.idx + 1
}
})
}
const handleOffsetSave = () => {
const direction = currentWallLineRef.current.direction
let canDirections = direction === 'left' || direction === 'right' ? ['up', 'down'] : ['left', 'right']
const currentIdx = currentWallLineRef.current.idx
if (!canDirections.includes(arrow1Ref.current)) {
alert('방향을 다시 선택하세요')
return
}
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
const idx = currentWallLineRef.current.idx
const prevIdx = idx - 1 <= 0 ? outerLines.length : idx - 1
const nextIdx = idx + 1 > outerLines.length ? 1 : idx + 1
const currentLine = currentWallLineRef.current
const prevLine = outerLines.find((line) => line.idx === prevIdx)
const nextLine = outerLines.find((line) => line.idx === nextIdx)
const length = length1Ref.current.value / 10
const currentLineX = Math.floor(Math.max(currentLine.x1, currentLine.x2))
const currentLineY = Math.floor(Math.max(currentLine.y1, currentLine.y2))
switch (arrow1Ref.current) {
case 'up': {
if (prevLine.direction === currentLine.direction) {
const newX =
currentLine.direction === 'left'
? Math.floor(Math.max(currentLine.x1, currentLine.x2))
: Math.floor(Math.min(currentLine.x1, currentLine.x2))
const newPoint1 = { x: newX, y: currentLineY - length }
const newPoint2 = { x: prevLine.x2, y: prevLine.y2 }
rearrangeOuterLine(currentIdx)
drawLine(newPoint1, newPoint2, currentIdx, 'top')
if (Math.abs(currentLineY - nextLine.y1) < 2) {
nextLine.set({ y1: currentLineY - length })
} else {
nextLine.set({ y2: currentLineY - length })
}
} else if (nextLine.direction === currentLine.direction) {
const newX =
currentLine.direction === 'left'
? Math.floor(Math.min(currentLine.x1, currentLine.x2))
: Math.floor(Math.max(currentLine.x1, currentLine.x2))
const newPoint1 = { x: newX, y: currentLineY - length }
const newPoint2 = { x: nextLine.x1, y: nextLine.y1 }
rearrangeOuterLine(currentIdx + 1)
drawLine(newPoint1, newPoint2, currentIdx + 1, 'top')
if (Math.abs(currentLineY - prevLine.y1) < 2) {
prevLine.set({ y1: currentLineY - length })
} else {
prevLine.set({ y2: currentLineY - length })
}
} else {
if (Math.abs(currentLineY - prevLine.y1) < 2) {
prevLine.set({ y1: prevLine.y1 - length })
} else {
prevLine.set({ y2: prevLine.y2 - length })
}
if (Math.abs(currentLineY - nextLine.y1) < 2) {
nextLine.set({ y1: nextLine.y1 - length })
} else {
nextLine.set({ y2: nextLine.y2 - length })
}
}
currentLine.set({ y1: currentLine.y1 - length, y2: currentLine.y2 - length })
break
}
case 'down': {
if (prevLine.direction === currentLine.direction) {
const newX =
currentLine.direction === 'left'
? Math.floor(Math.max(currentLine.x1, currentLine.x2))
: Math.floor(Math.min(currentLine.x1, currentLine.x2))
const newPoint1 = { x: newX, y: currentLineY + length }
const newPoint2 = { x: prevLine.x2, y: prevLine.y2 }
rearrangeOuterLine(currentIdx)
drawLine(newPoint1, newPoint2, currentIdx, 'bottom')
if (Math.abs(currentLineY - nextLine.y1) < 2) {
nextLine.set({ y1: currentLineY + length })
} else {
nextLine.set({ y2: currentLineY + length })
}
} else if (nextLine.direction === currentLine.direction) {
const newX =
currentLine.direction === 'left'
? Math.floor(Math.min(currentLine.x1, currentLine.x2))
: Math.floor(Math.max(currentLine.x1, currentLine.x2))
const newPoint1 = { x: newX, y: currentLineY + length }
const newPoint2 = { x: nextLine.x1, y: nextLine.y1 }
rearrangeOuterLine(currentIdx + 1)
drawLine(newPoint1, newPoint2, currentIdx + 1, 'bottom')
if (Math.abs(currentLineY - prevLine.y1) < 2) {
prevLine.set({ y1: currentLineY + length })
} else {
prevLine.set({ y2: currentLineY + length })
}
} else {
if (Math.abs(currentLineY - prevLine.y1) < 2) {
prevLine.set({ y1: prevLine.y1 + length })
} else {
prevLine.set({ y2: prevLine.y2 + length })
}
if (Math.abs(currentLineY - nextLine.y1) < 2) {
nextLine.set({ y1: nextLine.y1 + length })
} else {
nextLine.set({ y2: nextLine.y2 + length })
}
}
currentLine.set({ y1: currentLine.y1 + length, y2: currentLine.y2 + length })
break
}
case 'left': {
if (prevLine.direction === currentLine.direction) {
const newY =
currentLine.direction === 'top'
? Math.floor(Math.max(currentLine.y1, currentLine.y2))
: Math.floor(Math.min(currentLine.y1, currentLine.y2))
const newPoint1 = { x: currentLineX - length, y: newY }
const newPoint2 = { x: prevLine.x2, y: prevLine.y2 }
rearrangeOuterLine(currentIdx)
drawLine(newPoint1, newPoint2, currentIdx, 'left')
if (Math.abs(currentLineX - nextLine.x1) < 2) {
nextLine.set({ x1: currentLineX - length })
} else {
nextLine.set({ x2: currentLineX - length })
}
} else if (nextLine.direction === currentLine.direction) {
const newY =
currentLine.direction === 'top'
? Math.floor(Math.min(currentLine.y1, currentLine.y2))
: Math.floor(Math.max(currentLine.y1, currentLine.y2))
const newPoint1 = { x: currentLineX - length, y: newY }
const newPoint2 = { x: nextLine.x1, y: nextLine.y1 }
rearrangeOuterLine(currentIdx + 1)
drawLine(newPoint1, newPoint2, currentIdx + 1, 'left')
if (Math.abs(currentLineX - prevLine.x1) < 2) {
prevLine.set({ x1: currentLineX - length })
} else {
prevLine.set({ x2: currentLineX - length })
}
} else {
if (Math.abs(currentLineX - prevLine.x1) < 2) {
prevLine.set({ x1: prevLine.x1 - length })
} else {
prevLine.set({ x2: prevLine.x2 - length })
}
if (Math.abs(currentLineX - nextLine.x1) < 2) {
nextLine.set({ x1: nextLine.x1 - length })
} else {
nextLine.set({ x2: nextLine.x2 - length })
}
}
currentLine.set({ x1: currentLine.x1 - length, x2: currentLine.x2 - length })
break
}
case 'right': {
if (prevLine.direction === currentLine.direction) {
const newY =
currentLine.direction === 'top'
? Math.floor(Math.max(currentLine.y1, currentLine.y2))
: Math.floor(Math.min(currentLine.y1, currentLine.y2))
const newPoint1 = { x: currentLineX + length, y: newY }
const newPoint2 = { x: prevLine.x2, y: prevLine.y2 }
rearrangeOuterLine(currentIdx)
drawLine(newPoint1, newPoint2, currentIdx, 'right')
if (Math.abs(currentLineX - nextLine.x1) < 2) {
nextLine.set({ x1: currentLineX + length })
} else {
nextLine.set({ x2: currentLineX + length })
}
} else if (nextLine.direction === currentLine.direction) {
const newY =
currentLine.direction === 'top'
? Math.floor(Math.min(currentLine.y1, currentLine.y2))
: Math.floor(Math.max(currentLine.y1, currentLine.y2))
const newPoint1 = { x: currentLineX + length, y: newY }
const newPoint2 = { x: nextLine.x1, y: nextLine.y1 }
rearrangeOuterLine(currentIdx + 1)
drawLine(newPoint1, newPoint2, currentIdx + 1, 'right')
if (Math.abs(currentLineX - prevLine.x1) < 2) {
prevLine.set({ x1: currentLineX + length })
} else {
prevLine.set({ x2: currentLineX + length })
}
} else {
if (Math.abs(currentLineX - prevLine.x1) < 2) {
prevLine.set({ x1: prevLine.x1 + length })
} else {
prevLine.set({ x2: prevLine.x2 + length })
}
if (Math.abs(currentLineX - nextLine.x1) < 2) {
nextLine.set({ x1: nextLine.x1 + length })
} else {
nextLine.set({ x2: nextLine.x2 + length })
}
}
currentLine.set({ x1: currentLine.x1 + length, x2: currentLine.x2 + length })
break
}
}
canvas.renderAll()
}
return {
type,
setType,
buttonMenu,
TYPES,
length1Ref,
length2Ref,
radioTypeRef,
currentWallLineRef,
arrow1Ref,
arrow2Ref,
handleSave,
wallLineEditRef,
}
}