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

813 lines
25 KiB
JavaScript

import { useEffect, useRef, useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { useRecoilState, 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, getDegreeByChon } from '@/util/canvas-util'
import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting'
import {
addedRoofsState,
basicSettingState,
correntObjectNoState,
selectedRoofMaterialSelector,
settingModalFirstOptionsState,
} from '@/store/settingAtom'
import { useAxios } from '@/hooks/useAxios'
import { globalLocaleStore } from '@/store/localeAtom'
// 지붕형상 설정
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 selectedRoofMaterial = useRecoilValue(selectedRoofMaterialSelector)
const [pitch, setPitch] = useState(currentAngleType === ANGLE_TYPE.SLOPE ? selectedRoofMaterial.pitch : selectedRoofMaterial.angle) // 경사
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 ? selectedRoofMaterial.pitch : selectedRoofMaterial.angle) // 팔작지붕 폭
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, addPopup } = usePopup()
const settingModalFirstOptions = useRecoilValue(settingModalFirstOptionsState)
const [addedRoofs, setAddedRoofs] = useRecoilState(addedRoofsState)
const [basicSetting, setBasicSetting] = useRecoilState(basicSettingState)
const correntObjectNo = useRecoilValue(correntObjectNoState)
const globalLocaleState = useRecoilValue(globalLocaleStore)
const { post } = useAxios(globalLocaleState)
const { addLine, removeLine } = useLine()
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(() => {
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)
line.bringToFront()
}
})
canvas.renderAll()
}
}, [])
useEffect(() => {
if (shapeNum !== 4) {
return
}
if (!currentObject) {
return
}
if (currentObject.name !== 'outerLine') {
return
}
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 = () => {
let outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
let direction
if ([1, 2, 3, 5, 6, 7, 8].includes(shapeNum)) {
// 변별로 설정이 아닌 경우 경사를 지붕재에 적용해주어야함
setRoofPitch()
}
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')
let isValid = outerLines.every((line) => line.attributes?.isFixed)
if (!isValid) {
swalFire({
text: getMessage('modal.canvas.setting.roofline.properties.setting.not.setting'),
type: 'alert',
icon: 'warning',
})
return
}
const pitch = outerLines.find((line) => line.attributes.type === LINE_TYPE.WALLLINE.SHED)?.attributes.pitch
// 변별로 설정중 한쪽흐름일 경우 한쪽흐름의 pitch로 설정
if (pitch) {
outerLines.forEach((line) => {
if (line.attributes.type === LINE_TYPE.WALLLINE.SHED) {
line.attributes = {
...line.attributes,
pitch: pitchRef.current,
onlyOffset: true,
}
switch (line.direction) {
case 'bottom':
direction = 'east'
break
case 'top':
direction = 'west'
break
case 'left':
direction = 'south'
break
case 'right':
direction = 'north'
break
}
}
})
}
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: pitchRef.current,
type: LINE_TYPE.WALLLINE.SHED,
onlyOffset: true,
}
}
} 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,
onlyOffset: true,
}
}
}
// 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,
onlyOffset: true,
}
}
} 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,
onlyOffset: true,
}
}
}
// 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,
onlyOffset: true,
}
}
} 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,
onlyOffset: true,
}
}
}
// 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,
onlyOffset: true,
}
}
} 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,
onlyOffset: true,
}
}
}
// 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 && !obj.isFixed)
.forEach((obj) => {
canvas.remove(...obj.innerLines)
canvas.remove(obj)
})
const removeTargets = canvas
.getObjects()
.filter(
(obj) =>
(obj.name === 'pitchText' || obj.name === 'lengthText') &&
canvas.getObjects().find((parent) => parent.id === obj.parentId)?.name !== POLYGON_TYPE.ROOF,
)
removeTargets.forEach((obj) => {
canvas.remove(obj)
})
const polygon = addPolygonByLines(outerLines, {
name: POLYGON_TYPE.WALL,
direction,
originX: 'center',
originY: 'center',
})
// polygon.setViewLengthText(false)
polygon.lines = [...outerLines]
addPitchTextsByOuterLines()
const roof = drawRoofPolygon(polygon)
canvas?.renderAll()
roof.drawHelpLine(settingModalFirstOptions)
isFixRef.current = true
addPopup(id, 1, <RoofAllocationSetting id={id} pos={{ x: 50, y: 230 }} />)
}
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)
}
// 저장된 경사를 addedRoof 첫번째요소, basicSettings의 selectedRoofMaterial에 적용
const setRoofPitch = () => {
const newAddedRoofs = addedRoofs.map((roof, index) => {
if (index === 0) {
return { ...roof, pitch: Number(pitchRef.current), angle: getDegreeByChon(pitchRef.current) }
} else {
return { ...roof }
}
})
const newBasicSetting = { ...basicSetting, selectedRoofMaterial: { ...newAddedRoofs[0] } }
try {
basicSettingSave(newAddedRoofs)
setBasicSetting(newBasicSetting)
setAddedRoofs(newAddedRoofs)
} catch (error) {
swalFire({ text: error.message, icon: 'error' })
}
}
/**
* 지붕면 할당 저장
*/
const basicSettingSave = async (newAddedRoofs) => {
try {
const patternData = {
objectNo: correntObjectNo,
planNo: Number(basicSetting.planNo),
roofSizeSet: Number(basicSetting.roofSizeSet),
roofAngleSet: basicSetting.roofAngleSet,
roofAllocationList: newAddedRoofs.map((item, index) => ({
planNo: Number(basicSetting.planNo),
roofApply: item.selected,
roofSeq: index,
roofMatlCd: item.roofMatlCd === null || item.roofMatlCd === undefined ? 'ROOF_ID_WA_53A' : item.roofMatlCd,
roofWidth: item.width === null || item.width === undefined ? 0 : Number(item.width),
roofHeight: item.length === null || item.length === undefined ? 0 : Number(item.length),
roofHajebichi: item.hajebichi === null || item.hajebichi === undefined ? 0 : Number(item.hajebichi),
roofGap: !item.raft ? item.raftBaseCd : item.raft,
roofLayout: item.layout === null || item.layout === undefined ? 'P' : item.layout,
roofPitch: item.pitch === null || item.pitch === undefined ? 4 : Number(item.pitch),
roofAngle: item.angle === null || item.angle === undefined ? 21.8 : Number(item.angle),
})),
}
await post({ url: `/api/canvas-management/roof-allocation-settings`, data: patternData })
//Recoil 설정
//setCanvasSetting({ ...basicSetting })
} catch (error) {
swalFire({ text: error.message, icon: 'error' })
}
}
// 동, 서 선택 시 가로라인을 케라바로 설정
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: currentAngleType === ANGLE_TYPE.SLOPE ? pitch : getChonByDegree(pitch),
type: LINE_TYPE.WALLLINE.EAVES,
onlyOffset: false,
}
// 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: currentAngleType === ANGLE_TYPE.SLOPE ? pitch : getChonByDegree(pitch),
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: currentAngleType === ANGLE_TYPE.SLOPE ? pitch : getChonByDegree(pitch),
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,
}
selectedLine.attributes = { ...attributes, isFixed: true }
addPitchText(currentObject)
selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#45CD7D' })
break
}
case 2: {
// 케라바
attributes = {
type: LINE_TYPE.WALLLINE.GABLE,
offset: gableOffset / 10,
}
selectedLine.attributes = { ...attributes, isFixed: true }
selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#3FBAE6' })
break
}
case 3: {
// 벽
attributes = {
type: LINE_TYPE.WALLLINE.WALL,
offset: hasSleeve === '0' ? 0 : sleeveOffset / 10,
}
selectedLine.attributes = { ...attributes, isFixed: true }
break
}
case 4: {
// 팔작지붕
attributes = {
type: LINE_TYPE.WALLLINE.HIPANDGABLE,
pitch: pitchRef.current,
offset: eavesOffset / 10,
width: hipAndGableWidth / 10,
}
selectedLine.attributes = { ...attributes, isFixed: true }
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,
}
selectedLine.attributes = { ...attributes, isFixed: true }
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,
offset: shedWidth / 10,
}
selectedLine.attributes = { ...attributes, isFixed: true }
addPitchText(currentObject)
selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#000000' })
break
}
}
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]
history.current.push(selectedLine)
if (nextLine.attributes?.isFixed) {
canvas.discardActiveObject()
return
}
canvas.setActiveObject(nextLine)
}
// 변별로 설정 내 일변 전으로 돌아가기
const handleRollBack = () => {
if (history.current.length === 0) {
canvas.discardActiveObject()
return
}
const lastLine = history.current.pop()
canvas.setActiveObject(lastLine)
currentObject?.set({
stroke: '#000000',
strokeWidth: 4,
attributes: { isFixed: false },
})
lastLine.set({
stroke: '#000000',
strokeWidth: 4,
attributes: { isFixed: false },
})
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,
}
}