qcast-front/src/hooks/roofcover/useRoofShapeSetting.js

669 lines
19 KiB
JavaScript

import { useEffect, useRef, useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { useRecoilValue, useSetRecoilState } from 'recoil'
import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, currentMenuState, currentObjectState, pitchTextSelector } from '@/store/canvasAtom'
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
import { usePolygon } from '@/hooks/usePolygon'
import { useMode } from '@/hooks/useMode'
import { useLine } from '@/hooks/useLine'
import { outerLineFixState } from '@/store/outerLineAtom'
import { useSwal } from '@/hooks/useSwal'
import { usePopup } from '@/hooks/usePopup'
import { getChonByDegree } from '@/util/canvas-util'
// 지붕형상 설정
export function useRoofShapeSetting(id) {
const [shapeNum, setShapeNum] = useState(1)
const [buttonAct, setButtonAct] = useState(1)
const { swalFire } = useSwal()
const { getMessage } = useMessage()
const canvas = useRecoilValue(canvasState)
const currentAngleType = useRecoilValue(currentAngleTypeSelector)
const pitchText = useRecoilValue(pitchTextSelector)
const { addPolygonByLines } = usePolygon()
const [pitch, setPitch] = useState(currentAngleType === ANGLE_TYPE.SLOPE ? 4 : 21.8) // 경사
const [eavesOffset, setEavesOffset] = useState(500) // 처마출폭
const [gableOffset, setGableOffset] = useState(300) // 케라바출폭
const [sleeveOffset, setSleeveOffset] = useState(300) // 소매출폭
const [jerkinHeadWidth, setJerkinHeadWidth] = useState(800) // 반절처 폭
const [jerkinHeadPitch, setJerkinHeadPitch] = useState(currentAngleType === ANGLE_TYPE.SLOPE ? 4.5 : 20) // 반절처 경사
const [hipAndGableWidth, setHipAndGableWidth] = useState(800) // 팔작지붕 폭
const [shedPitch, setShedPitch] = useState(currentAngleType === ANGLE_TYPE.SLOPE ? 4 : 21.8) // 팔작지붕 폭
const [shedWidth, setShedWidth] = useState(300) // 한쪽흐름 폭
const [hasSleeve, setHasSleeve] = useState('0')
const currentObject = useRecoilValue(currentObjectState)
const { drawRoofPolygon } = useMode()
const { hideLine, showLine, removePitchText, addPitchText, addPitchTextsByOuterLines } = useLine()
const setCurrentMenu = useSetRecoilState(currentMenuState)
const outerLineFix = useRecoilValue(outerLineFixState)
const isFixRef = useRef(false)
const pitchRef = useRef(null)
const shedPitchRef = useRef(null)
const jerkinHeadPitchRef = useRef(null)
const history = useRef([])
const { closePopup } = usePopup()
useEffect(() => {
pitchRef.current = currentAngleType === ANGLE_TYPE.SLOPE ? pitch : getChonByDegree(pitch)
}, [pitch])
useEffect(() => {
shedPitchRef.current = currentAngleType === ANGLE_TYPE.SLOPE ? shedPitch : getChonByDegree(shedPitch)
}, [shedPitch])
useEffect(() => {
jerkinHeadPitchRef.current = currentAngleType === ANGLE_TYPE.SLOPE ? jerkinHeadPitch : getChonByDegree(jerkinHeadPitch)
}, [jerkinHeadPitch])
useEffect(() => {
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
if (!outerLineFix || outerLines.length === 0) {
swalFire({ text: '외벽선이 없습니다.' })
// setShowRoofShapeSettingModal(false)
closePopup(id)
}
return () => {
if (!isFixRef.current) {
return
}
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
const pitchTexts = canvas.getObjects().filter((obj) => obj.name === 'pitchText')
canvas.remove(...pitchTexts)
outerLines.forEach((line) => {
let stroke, strokeWidth
if (line.attributes) {
if (line.attributes.type === LINE_TYPE.WALLLINE.EAVES || line.attributes.type === LINE_TYPE.WALLLINE.HIPANDGABLE) {
stroke = '#45CD7D'
strokeWidth = 4
} else if (line.attributes.type === LINE_TYPE.WALLLINE.GABLE || line.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) {
stroke = '#3FBAE6'
strokeWidth = 4
} else {
stroke = '#000000'
strokeWidth = 4
}
line.set({
stroke,
strokeWidth,
})
addPitchText(line)
}
})
canvas.renderAll()
}
}, [])
useEffect(() => {
if (shapeNum !== 4) {
return
}
if (!currentObject) {
return
}
if (currentObject.name !== 'outerLine') {
return
}
/*const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
outerLines.forEach((line) => {
line.set({
stroke: '#000000',
strokeWidth: 4,
})
})*/
currentObject.set({
stroke: '#EA10AC',
strokeWidth: 4,
})
canvas.renderAll()
}, [currentObject])
useEffect(() => {
if (shapeNum === 4) {
canvas?.remove(canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.WALL))
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
outerLines.forEach((line) => {
showLine(line)
line.bringToFront()
})
canvas?.renderAll()
}
setEavesOffset(500)
setGableOffset(300)
setSleeveOffset(300)
setJerkinHeadWidth(800)
setHipAndGableWidth(800)
setShedWidth(300)
}, [shapeNum])
const shapeMenu = [
{ id: 1, name: getMessage('modal.roof.shape.setting.ridge') }, // 용마루
{ id: 2, name: getMessage('modal.roof.shape.setting.patten.a') }, // 패턴A
{ id: 3, name: getMessage('modal.roof.shape.setting.patten.b') }, // 패턴B
{ id: 4, name: getMessage('modal.roof.shape.setting.side') }, // 변별로 설정
{ id: 5, name: getMessage('commons.west') }, // 서
{ id: 6, name: getMessage('commons.east') }, // 동
{ id: 7, name: getMessage('commons.south') }, // 남
{ id: 8, name: getMessage('commons.north') }, // 북
]
const buttonMenu = [
{ id: 1, name: getMessage('eaves') },
{ id: 2, name: getMessage('gable') },
{ id: 3, name: getMessage('wall') },
{ id: 4, name: getMessage('hipandgable') },
{ id: 5, name: getMessage('jerkinhead') },
{ id: 6, name: getMessage('shed') },
]
const handleSave = () => {
//기존 wallLine 삭제
let outerLines
let direction
switch (shapeNum) {
case 1: {
outerLines = saveRidge()
break
}
case 2: {
outerLines = saveAPattern()
break
}
case 3: {
outerLines = saveBPattern()
break
}
case 4: {
outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
outerLines.forEach((line) => {
// hideLine(line)
})
break
}
case 5: {
// 서쪽
initLineSetting()
outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
direction = 'west'
outerLines.forEach((line) => {
setWestAndEastRoof(line)
if (outerLines[0].direction === 'bottom') {
if (line.direction === 'bottom') {
line.attributes = {
offset: eavesOffset / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.EAVES,
}
}
if (line.direction === 'top') {
line.attributes = {
offset: shedWidth / 10,
pitch: pitch,
type: LINE_TYPE.WALLLINE.SHED,
}
}
} else {
if (line.direction === 'top') {
line.attributes = {
offset: eavesOffset / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.EAVES,
}
}
if (line.direction === 'bottom') {
line.attributes = {
offset: shedWidth / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.SHED,
}
}
}
// hideLine(line)
})
break
}
case 6: {
initLineSetting()
outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
direction = 'east'
outerLines.forEach((line) => {
setWestAndEastRoof(line)
if (outerLines[0].direction === 'bottom') {
if (line.direction === 'top') {
line.attributes = {
offset: eavesOffset / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.EAVES,
}
}
if (line.direction === 'bottom') {
line.attributes = {
offset: shedWidth / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.SHED,
}
}
} else {
if (line.direction === 'bottom') {
line.attributes = {
offset: eavesOffset / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.EAVES,
}
}
if (line.direction === 'top') {
line.attributes = {
offset: shedWidth / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.SHED,
}
}
}
// hideLine(line)
})
break
}
case 7: {
initLineSetting()
outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
direction = 'south'
outerLines.forEach((line) => {
setSouthAndNorthRoof(line)
if (outerLines[0].direction === 'bottom') {
if (line.direction === 'right') {
line.attributes = {
offset: eavesOffset / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.EAVES,
}
}
if (line.direction === 'left') {
line.attributes = {
offset: shedWidth / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.SHED,
}
}
} else {
if (line.direction === 'left') {
line.attributes = {
offset: eavesOffset / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.EAVES,
}
}
if (line.direction === 'right') {
line.attributes = {
offset: shedWidth / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.SHED,
}
}
}
// hideLine(line)
})
break
}
case 8: {
initLineSetting()
outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
direction = 'north'
outerLines.forEach((line) => {
setSouthAndNorthRoof(line)
if (outerLines[0].direction === 'bottom') {
if (line.direction === 'left') {
line.attributes = {
offset: eavesOffset / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.EAVES,
}
}
if (line.direction === 'right') {
line.attributes = {
offset: shedWidth / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.SHED,
}
}
} else {
if (line.direction === 'right') {
line.attributes = {
offset: eavesOffset / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.EAVES,
}
}
if (line.direction === 'left') {
line.attributes = {
offset: shedWidth / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.SHED,
}
}
}
// hideLine(line)
})
break
}
}
// 기존 wallLine, roofBase 제거
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.WALL)
.forEach((line) => {
canvas.remove(line)
})
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.ROOF)
.forEach((obj) => {
canvas.remove(...obj.innerLines)
canvas.remove(obj)
})
const polygon = addPolygonByLines(outerLines, { name: POLYGON_TYPE.WALL, direction })
polygon.lines = [...outerLines]
addPitchTextsByOuterLines()
const roof = drawRoofPolygon(polygon)
canvas?.renderAll()
roof.drawHelpLine()
// setShowRoofShapeSettingModal(false)
isFixRef.current = true
closePopup(id)
}
const initLineSetting = () => {
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
const tempPolygon = addPolygonByLines(outerLines)
tempPolygon.lines.forEach((line) => {
outerLines.forEach((outerLine) => {
if (
(line.startPoint === outerLine.startPoint && line.endPoint === outerLine.endPoint) ||
(line.startPoint === outerLine.endPoint && line.endPoint === outerLine.startPoint)
) {
outerLine.direction = line.direction
outerLine.idx = line.idx
}
})
})
// 첫번째 line의 방향이 right일 경우
if (outerLines[0].direction === 'right') {
// top과 bottom의 방향을 바꾼다.
outerLines.forEach((line) => {
if (line.direction === 'top') {
line.direction = 'bottom'
} else if (line.direction === 'bottom') {
line.direction = 'top'
}
})
}
canvas.remove(tempPolygon)
}
// 동, 서 선택 시 가로라인을 케라바로 설정
const setWestAndEastRoof = (line) => {
if (line.direction === 'left' || line.direction === 'right') {
line.attributes = {
offset: gableOffset / 10,
type: LINE_TYPE.WALLLINE.GABLE,
}
}
}
// 남, 북 선택 시 세로라인을 케라바로 설정
const setSouthAndNorthRoof = (line) => {
if (line.direction === 'top' || line.direction === 'bottom') {
line.attributes = {
offset: gableOffset / 10,
type: LINE_TYPE.WALLLINE.GABLE,
}
}
}
const saveRidge = () => {
// 용마루 저장
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
outerLines.forEach((line) => {
line.attributes = {
offset: eavesOffset / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.EAVES,
}
// hideLine(line)
})
return outerLines
}
// 패턴 A : 가로선이 모두 케라바
const saveAPattern = () => {
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
outerLines.forEach((line) => {
if (line.direction === 'left' || line.direction === 'right') {
line.attributes = {
offset: gableOffset / 10,
type: LINE_TYPE.WALLLINE.GABLE,
}
} else if (line.direction === 'top' || line.direction === 'bottom') {
line.attributes = {
offset: eavesOffset / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.EAVES,
}
}
// hideLine(line)
})
return outerLines
}
// 패턴 B : 세로선이 모두 케라바
const saveBPattern = () => {
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
outerLines.forEach((line) => {
if (line.direction === 'top' || line.direction === 'bottom') {
line.attributes = {
offset: gableOffset / 10,
type: LINE_TYPE.WALLLINE.GABLE,
}
} else if (line.direction === 'left' || line.direction === 'right') {
line.attributes = {
offset: eavesOffset / 10,
pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.EAVES,
}
}
// hideLine(line)
})
return outerLines
}
// 변별로 설정 팝업 내 적용
const handleConfirm = () => {
const selectedLine = canvas?.getActiveObject()
if (!selectedLine) {
return
}
let attributes
switch (buttonAct) {
case 1: {
// 처마
attributes = {
type: LINE_TYPE.WALLLINE.EAVES,
pitch: pitchRef.current,
offset: eavesOffset / 10,
}
addPitchText(currentObject)
selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#45CD7D' })
break
}
case 2: {
// 케라바
attributes = {
type: LINE_TYPE.WALLLINE.GABLE,
offset: gableOffset / 10,
}
selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#3FBAE6' })
break
}
case 3: {
// 벽
attributes = {
type: LINE_TYPE.WALLLINE.WALL,
width: hasSleeve === '0' ? 0 : sleeveOffset / 10,
sleeve: hasSleeve === '1',
}
break
}
case 4: {
// 팔작지붕
attributes = {
type: LINE_TYPE.WALLLINE.HIPANDGABLE,
pitch: pitchRef.current,
offset: eavesOffset / 10,
width: hipAndGableWidth / 10,
}
addPitchText(currentObject)
selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#45CD7D' })
break
}
case 5: {
// 반절처
attributes = {
type: LINE_TYPE.WALLLINE.JERKINHEAD,
offset: gableOffset / 10,
width: jerkinHeadWidth / 10,
pitch: jerkinHeadPitchRef.current,
}
addPitchText(currentObject)
selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#3FBAE6' })
break
}
case 6: {
// 한쪽흐름
attributes = {
type: LINE_TYPE.WALLLINE.SHED,
pitch: shedPitchRef.current,
width: shedWidth / 10,
}
addPitchText(currentObject)
selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#000000' })
break
}
}
selectedLine.attributes = attributes
history.current.push(selectedLine)
canvas.renderAll()
nextLineFocus(selectedLine)
}
const nextLineFocus = (selectedLine) => {
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
const index = lines.findIndex((line) => line.idx === selectedLine.idx)
const nextLine = lines[index + 1] || lines[0]
canvas.setActiveObject(nextLine)
}
// 변별로 설정 내 일변 전으로 돌아가기
const handleRollBack = () => {
if (history.current.length === 0) {
return
}
const lastLine = history.current.pop()
currentObject.set({
stroke: '#000000',
strokeWidth: 4,
})
lastLine.set({
stroke: '#000000',
strokeWidth: 4,
})
canvas.setActiveObject(lastLine)
canvas.renderAll()
}
return {
shapeNum,
setShapeNum,
shapeMenu,
handleSave,
buttonMenu,
pitch,
setPitch,
eavesOffset,
setEavesOffset,
gableOffset,
setGableOffset,
sleeveOffset,
setSleeveOffset,
jerkinHeadWidth,
setJerkinHeadWidth,
jerkinHeadPitch,
setJerkinHeadPitch,
hipAndGableWidth,
setHipAndGableWidth,
shedWidth,
setShedWidth,
hasSleeve,
setHasSleeve,
buttonAct,
setButtonAct,
handleConfirm,
handleRollBack,
pitchText,
shedPitch,
setShedPitch,
}
}