# Conflicts: # src/common/common.js # src/components/floor-plan/CanvasFrame.jsx # src/hooks/roofcover/useWallLineOffsetSetting.js # src/util/qpolygon-utils.js
523 lines
18 KiB
JavaScript
523 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'
|
|
import Big from 'big.js'
|
|
import { outerLineFixState } from '@/store/outerLineAtom'
|
|
|
|
// 외벽선 편집 및 오프셋
|
|
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 outerLineFix = useRecoilValue(outerLineFixState)
|
|
|
|
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()
|
|
|
|
canvas
|
|
.getObjects()
|
|
.filter((obj) => obj.name === 'outerLine')
|
|
.forEach((obj) => obj.fire('modified'))
|
|
}
|
|
|
|
/**
|
|
* outreLine의 index를 조절한다.
|
|
* @param idxParam
|
|
* @param isNegative
|
|
*/
|
|
const reArrangeOuterLine = (idxParam, isNegative = false) => {
|
|
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
|
outerLines.forEach((outerLine) => {
|
|
if (outerLine.idx >= idxParam) {
|
|
outerLine.idx = isNegative ? outerLine.idx - 1 : outerLine.idx + 1
|
|
}
|
|
})
|
|
}
|
|
|
|
/**
|
|
* offset 저장
|
|
*/
|
|
const handleOffsetSave = () => {
|
|
if (!currentObject) return
|
|
const currentLine = currentObject
|
|
const currentVector = currentLine.y1 === currentLine.y2 ? 'horizontal' : 'vertical'
|
|
const canDirections = currentVector === 'horizontal' ? ['up', 'down'] : ['left', 'right']
|
|
if (!canDirections.includes(arrow1Ref.current)) {
|
|
alert('방향을 다시 선택하세요')
|
|
return
|
|
}
|
|
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
|
outerLines.sort((a, b) => a.idx - b.idx)
|
|
|
|
const currentIdx = currentLine.idx
|
|
const prevIdx = currentIdx - 1 <= 0 ? outerLines.length : currentIdx - 1
|
|
const nextIdx = currentLine.idx + 1 > outerLines.length ? 1 : currentIdx + 1
|
|
|
|
const prevLine = outerLines.find((line) => line.idx === prevIdx)
|
|
const nextLine = outerLines.find((line) => line.idx === nextIdx)
|
|
const prevVector = prevLine.y1 === prevLine.y2 ? 'horizontal' : 'vertical'
|
|
const nextVector = nextLine.y1 === nextLine.y2 ? 'horizontal' : 'vertical'
|
|
|
|
const offsetLength = Big(Number(length1Ref.current.value)).div(10)
|
|
if (offsetLength.eq(0)) return
|
|
|
|
const currentLineMinX = Big(Math.max(currentLine.x1, currentLine.x2))
|
|
const currentLineMaxX = Big(Math.max(currentLine.x1, currentLine.x2))
|
|
const currentLineMinY = Big(Math.max(currentLine.y1, currentLine.y2))
|
|
const currentLineMaxY = Big(Math.max(currentLine.y1, currentLine.y2))
|
|
|
|
if (currentVector === 'horizontal') {
|
|
const prevX = currentLine.x1 < currentLine.x2 ? Math.min(currentLine.x1, currentLine.x2) : Math.max(currentLine.x1, currentLine.x2)
|
|
const nextX = currentLine.x1 < currentLine.x2 ? Math.max(currentLine.x1, currentLine.x2) : Math.min(currentLine.x1, currentLine.x2)
|
|
if (arrow1Ref.current === 'up') {
|
|
currentLine.set({ y1: currentLineMaxY.minus(offsetLength).toNumber(), y2: currentLineMaxY.minus(offsetLength).toNumber() })
|
|
if (prevVector === currentVector) {
|
|
const point1 = { x: prevX, y: prevLine.y2 }
|
|
const point2 = { x: prevX, y: currentLine.y1 }
|
|
reArrangeOuterLine(currentIdx)
|
|
drawLine(point1, point2, currentIdx, arrow1Ref.current)
|
|
} else {
|
|
if (Big(prevLine.y1).minus(currentLineMinY).abs().lte(Big(prevLine.y2).minus(currentLineMinY).abs())) {
|
|
prevLine.set({ y1: currentLine.y1 })
|
|
} else {
|
|
prevLine.set({ y2: currentLine.y1 })
|
|
}
|
|
if (Big(prevLine.y1).minus(Big(prevLine.y2)).eq(0)) {
|
|
reArrangeOuterLine(currentIdx - 1, true)
|
|
canvas.remove(prevLine)
|
|
}
|
|
}
|
|
if (nextVector === currentVector) {
|
|
const point1 = { x: nextX, y: nextLine.y2 }
|
|
const point2 = { x: nextX, y: currentLine.y1 }
|
|
reArrangeOuterLine(currentIdx + 1)
|
|
drawLine(point1, point2, currentIdx + 1, arrow1Ref.current)
|
|
} else {
|
|
if (Big(nextLine.y1).minus(currentLineMaxY).abs().lte(Big(nextLine.y2).minus(currentLineMaxY).abs())) {
|
|
nextLine.set({ y1: currentLine.y1 })
|
|
} else {
|
|
nextLine.set({ y2: currentLine.y1 })
|
|
}
|
|
if (Big(nextLine.y1).minus(Big(nextLine.y2)).eq(0)) {
|
|
reArrangeOuterLine(currentIdx + 1, true)
|
|
canvas.remove(nextLine)
|
|
}
|
|
}
|
|
}
|
|
if (arrow1Ref.current === 'down') {
|
|
currentLine.set({ y1: currentLineMaxY.plus(offsetLength).toNumber(), y2: currentLineMaxY.plus(offsetLength).toNumber() })
|
|
if (prevVector === currentVector) {
|
|
const point1 = { x: prevX, y: prevLine.y2 }
|
|
const point2 = { x: prevX, y: currentLine.y1 }
|
|
reArrangeOuterLine(currentIdx)
|
|
drawLine(point1, point2, currentIdx, arrow1Ref.current)
|
|
} else {
|
|
if (Big(prevLine.y1).minus(currentLineMinY).abs().lte(Big(prevLine.y2).minus(currentLineMinY).abs())) {
|
|
prevLine.set({ y1: currentLine.y1 })
|
|
} else {
|
|
prevLine.set({ y2: currentLine.y1 })
|
|
}
|
|
if (Big(prevLine.y1).minus(Big(prevLine.y2)).eq(0)) {
|
|
reArrangeOuterLine(currentIdx - 1, true)
|
|
canvas.remove(prevLine)
|
|
}
|
|
}
|
|
if (nextVector === currentVector) {
|
|
const point1 = { x: nextX, y: nextLine.y2 }
|
|
const point2 = { x: nextX, y: currentLine.y1 }
|
|
reArrangeOuterLine(currentIdx + 1)
|
|
drawLine(point1, point2, currentIdx + 1, arrow1Ref.current)
|
|
} else {
|
|
if (Big(nextLine.y1).minus(currentLineMaxY).abs().lte(Big(nextLine.y2).minus(currentLineMaxY).abs())) {
|
|
nextLine.set({ y1: currentLine.y1 })
|
|
} else {
|
|
nextLine.set({ y2: currentLine.y1 })
|
|
}
|
|
if (Big(nextLine.y1).minus(Big(nextLine.y2)).eq(0)) {
|
|
reArrangeOuterLine(currentIdx + 1, true)
|
|
canvas.remove(nextLine)
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
const prevY = currentLine.y1 < currentLine.y2 ? Math.min(currentLine.y1, currentLine.y2) : Math.max(currentLine.y1, currentLine.y2)
|
|
const nextY = currentLine.y1 < currentLine.y2 ? Math.max(currentLine.y1, currentLine.y2) : Math.min(currentLine.y1, currentLine.y2)
|
|
if (arrow1Ref.current === 'left') {
|
|
currentLine.set({ x1: currentLineMaxX.minus(offsetLength).toNumber(), x2: currentLineMaxX.minus(offsetLength).toNumber() })
|
|
|
|
if (prevVector === currentVector) {
|
|
const point1 = { x: prevLine.x2, y: prevY }
|
|
const point2 = { x: currentLine.x1, y: prevY }
|
|
reArrangeOuterLine(currentIdx)
|
|
drawLine(point1, point2, currentIdx, arrow1Ref.current)
|
|
} else {
|
|
if (Big(prevLine.x1).minus(currentLineMinX).abs().lte(Big(prevLine.x2).minus(currentLineMinX).abs())) {
|
|
prevLine.set({ x1: currentLine.x1 })
|
|
} else {
|
|
prevLine.set({ x2: currentLine.x1 })
|
|
}
|
|
if (Big(prevLine.x1).minus(Big(prevLine.x2)).eq(0)) {
|
|
reArrangeOuterLine(currentIdx - 1, true)
|
|
canvas.remove(prevLine)
|
|
}
|
|
}
|
|
if (nextVector === currentVector) {
|
|
const point1 = { x: currentLine.x2, y: nextY }
|
|
const point2 = { x: nextLine.x1, y: nextY }
|
|
reArrangeOuterLine(currentIdx + 1)
|
|
drawLine(point1, point2, currentIdx + 1, arrow1Ref.current)
|
|
} else {
|
|
if (Big(nextLine.x1).minus(currentLineMaxX).abs().lte(Big(nextLine.x2).minus(currentLineMaxX).abs())) {
|
|
nextLine.set({ x1: currentLine.x2 })
|
|
} else {
|
|
nextLine.set({ x2: currentLine.x2 })
|
|
}
|
|
if (Big(nextLine.x1).minus(Big(nextLine.x2)).eq(0)) {
|
|
reArrangeOuterLine(currentIdx + 1, true)
|
|
canvas.remove(nextLine)
|
|
}
|
|
}
|
|
}
|
|
if (arrow1Ref.current === 'right') {
|
|
currentLine.set({ x1: currentLineMaxX.plus(offsetLength).toNumber(), x2: currentLineMaxX.plus(offsetLength).toNumber() })
|
|
|
|
if (prevVector === currentVector) {
|
|
const point1 = { x: prevLine.x2, y: prevY }
|
|
const point2 = { x: currentLine.x1, y: prevY }
|
|
reArrangeOuterLine(currentIdx)
|
|
drawLine(point1, point2, currentIdx, arrow1Ref.current)
|
|
} else {
|
|
if (Big(prevLine.x1).minus(currentLineMinX).abs().lte(Big(prevLine.x2).minus(currentLineMinX).abs())) {
|
|
prevLine.set({ x1: currentLine.x1 })
|
|
} else {
|
|
prevLine.set({ x2: currentLine.x1 })
|
|
}
|
|
|
|
if (Big(prevLine.x1).minus(Big(prevLine.x2)).eq(0)) {
|
|
reArrangeOuterLine(currentIdx - 1, true)
|
|
canvas.remove(prevLine)
|
|
}
|
|
}
|
|
if (nextVector === currentVector) {
|
|
const point1 = { x: currentLine.x2, y: nextY }
|
|
const point2 = { x: nextLine.x1, y: nextY }
|
|
reArrangeOuterLine(currentIdx + 1)
|
|
drawLine(point1, point2, currentIdx + 1, arrow1Ref.current)
|
|
} else {
|
|
if (Big(nextLine.x1).minus(currentLineMaxX).abs().lte(Big(nextLine.x2).minus(currentLineMaxX).abs())) {
|
|
nextLine.set({ x1: currentLine.x2 })
|
|
} else {
|
|
nextLine.set({ x2: currentLine.x2 })
|
|
}
|
|
|
|
if (Big(nextLine.x1).minus(Big(nextLine.x2)).eq(0)) {
|
|
reArrangeOuterLine(currentIdx + 1, true)
|
|
canvas.remove(nextLine)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const newOuterLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
|
newOuterLines.sort((a, b) => a.idx - b.idx)
|
|
newOuterLines.forEach((line, idx) => {
|
|
line.fire('modified')
|
|
})
|
|
|
|
canvas.renderAll()
|
|
}
|
|
|
|
return {
|
|
type,
|
|
setType,
|
|
buttonMenu,
|
|
TYPES,
|
|
length1Ref,
|
|
length2Ref,
|
|
radioTypeRef,
|
|
currentWallLineRef,
|
|
arrow1Ref,
|
|
arrow2Ref,
|
|
handleSave,
|
|
wallLineEditRef,
|
|
}
|
|
}
|