diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index fec9e227..360c9ddc 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -169,8 +169,9 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { attributes: { offset: 0, }, + parent: this, direction: getDirectionByPoint(point, nextPoint), - idx: i, + idx: i + 1, }) line.startPoint = point line.endPoint = nextPoint diff --git a/src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx b/src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx index 517a7ba3..ccf38062 100644 --- a/src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx +++ b/src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx @@ -1,25 +1,73 @@ -import { useMessage } from '@/hooks/useMessage' import WithDraggable from '@/components/common/draggable/WithDraggable' import Ridge from '@/components/floor-plan/modal/roofShape/type/Ridge' import Pattern from '@/components/floor-plan/modal/roofShape/type/Pattern' import Side from '@/components/floor-plan/modal/roofShape/type/Side' -import { useState } from 'react' import Image from 'next/image' import Direction from '@/components/floor-plan/modal/roofShape/type/Direction' +import { useRoofShapeSetting } from '@/hooks/roofcover/useRoofShapeSetting' +import { useMessage } from '@/hooks/useMessage' export default function RoofShapeSetting({ setShowRoofShapeSettingModal }) { const { getMessage } = useMessage() - const [shapeNum, setShapeNum] = useState(1) - 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 { + shapeNum, + setShapeNum, + shapeMenu, + handleSave, + pitch, + setPitch, + eavesOffset, + setEavesOffset, + gableOffset, + setGableOffset, + sleeveOffset, + setSleeveOffset, + jerkinHeadWidth, + setJerkinHeadWidth, + jerkinHeadPitch, + setJerkinHeadPitch, + hipAndGableWidth, + setHipAndGableWidth, + shedWidth, + setShedWidth, + hasSleeve, + setHasSleeve, + buttonAct, + setButtonAct, + buttonMenu, + handleConfirm, + handleRollBack, + } = useRoofShapeSetting() + + const ridgeProps = { pitch, setPitch, eavesOffset, setEavesOffset } + const patternProps = { pitch, setPitch, eavesOffset, setEavesOffset, gableOffset, setGableOffset } + const sideProps = { + pitch, + setPitch, + eavesOffset, + setEavesOffset, + gableOffset, + setGableOffset, + sleeveOffset, + setSleeveOffset, + jerkinHeadWidth, + setJerkinHeadWidth, + jerkinHeadPitch, + setJerkinHeadPitch, + hipAndGableWidth, + setHipAndGableWidth, + shedWidth, + setShedWidth, + hasSleeve, + setHasSleeve, + buttonAct, + setButtonAct, + buttonMenu, + handleConfirm, + handleRollBack, + } + + const directionProps = { pitch, setPitch, eavesOffset, setEavesOffset, gableOffset, setGableOffset, shedWidth, setShedWidth } return ( @@ -43,13 +91,15 @@ export default function RoofShapeSetting({ setShowRoofShapeSettingModal }) {
{getMessage('setting')}
- {shapeNum === 1 && } - {(shapeNum === 2 || shapeNum === 3) && } - {shapeNum === 4 && } - {(shapeNum === 5 || shapeNum === 6 || shapeNum === 7 || shapeNum === 8) && } + {shapeNum === 1 && } + {(shapeNum === 2 || shapeNum === 3) && } + {shapeNum === 4 && } + {(shapeNum === 5 || shapeNum === 6 || shapeNum === 7 || shapeNum === 8) && }
- +
diff --git a/src/components/floor-plan/modal/roofShape/type/Direction.jsx b/src/components/floor-plan/modal/roofShape/type/Direction.jsx index a02258f9..51faffcb 100644 --- a/src/components/floor-plan/modal/roofShape/type/Direction.jsx +++ b/src/components/floor-plan/modal/roofShape/type/Direction.jsx @@ -1,6 +1,7 @@ import { useMessage } from '@/hooks/useMessage' +import { onlyNumberInputChange, onlyNumberWithDotInputChange } from '@/util/input-utils' -export default function Direction() { +export default function Direction({ pitch, setPitch, eavesOffset, setEavesOffset, gableOffset, setGableOffset, shedWidth, setShedWidth }) { const { getMessage } = useMessage() return (
@@ -9,7 +10,7 @@ export default function Direction() { {getMessage('slope')}
- + onlyNumberWithDotInputChange(e, setPitch)} />
{getMessage('size')}
@@ -18,7 +19,7 @@ export default function Direction() { {getMessage('eaves.offset')}
- + onlyNumberInputChange(e, setEavesOffset)} />
mm @@ -27,7 +28,7 @@ export default function Direction() { {getMessage('gable.offset')}
- + onlyNumberInputChange(e, setGableOffset)} />
mm @@ -36,7 +37,7 @@ export default function Direction() { {getMessage('windage.width')}
- + onlyNumberInputChange(e, setShedWidth)} />
mm diff --git a/src/components/floor-plan/modal/roofShape/type/Pattern.jsx b/src/components/floor-plan/modal/roofShape/type/Pattern.jsx index 606c154d..0c086fbe 100644 --- a/src/components/floor-plan/modal/roofShape/type/Pattern.jsx +++ b/src/components/floor-plan/modal/roofShape/type/Pattern.jsx @@ -1,7 +1,9 @@ import { useMessage } from '@/hooks/useMessage' +import { onlyNumberInputChange, onlyNumberWithDotInputChange } from '@/util/input-utils' -export default function Pattern() { +export default function Pattern(props) { const { getMessage } = useMessage() + const { pitch, setPitch, eavesOffset, setEavesOffset, gableOffset, setGableOffset } = props return (
@@ -9,7 +11,7 @@ export default function Pattern() { {getMessage('slope')}
- + onlyNumberWithDotInputChange(e, setPitch)} />
{getMessage('size')}
@@ -18,7 +20,7 @@ export default function Pattern() { {getMessage('eaves.offset')}
- + onlyNumberInputChange(e, setEavesOffset)} />
mm
@@ -27,7 +29,7 @@ export default function Pattern() { {getMessage('gable.offset')}
- +
mm diff --git a/src/components/floor-plan/modal/roofShape/type/Ridge.jsx b/src/components/floor-plan/modal/roofShape/type/Ridge.jsx index 7897046c..13dab6f3 100644 --- a/src/components/floor-plan/modal/roofShape/type/Ridge.jsx +++ b/src/components/floor-plan/modal/roofShape/type/Ridge.jsx @@ -1,7 +1,11 @@ import { useMessage } from '@/hooks/useMessage' +import { useEffect } from 'react' +import { onlyNumberInputChange, onlyNumberWithDotInputChange } from '@/util/input-utils' -export default function Ridge() { +export default function Ridge(props) { const { getMessage } = useMessage() + const { pitch, setPitch, eavesOffset, setEavesOffset } = props + return (
@@ -9,7 +13,7 @@ export default function Ridge() { {getMessage('slope')}
- + onlyNumberWithDotInputChange(e, setPitch)} />
{getMessage('size')}
@@ -18,7 +22,7 @@ export default function Ridge() { {getMessage('eaves.offset')}
- + onlyNumberInputChange(e, setEavesOffset)} />
mm
diff --git a/src/components/floor-plan/modal/roofShape/type/Side.jsx b/src/components/floor-plan/modal/roofShape/type/Side.jsx index 3fc1737c..b2f032ba 100644 --- a/src/components/floor-plan/modal/roofShape/type/Side.jsx +++ b/src/components/floor-plan/modal/roofShape/type/Side.jsx @@ -7,39 +7,68 @@ import Wall from '@/components/floor-plan/modal/roofShape/type/option/Wall' import Jerkinhead from '@/components/floor-plan/modal/roofShape/type/option/Jerkinhead' import Shed from '@/components/floor-plan/modal/roofShape/type/option/Shed' -export default function Side() { - const [buttonAct, setButtonAct] = useState(1) +export default function Side(props) { + const { + pitch, + setPitch, + eavesOffset, + setEavesOffset, + gableOffset, + setGableOffset, + sleeveOffset, + setSleeveOffset, + jerkinHeadWidth, + setJerkinHeadWidth, + jerkinHeadPitch, + setJerkinHeadPitch, + hipAndGableWidth, + setHipAndGableWidth, + shedWidth, + setShedWidth, + hasSleeve, + setHasSleeve, + buttonAct, + setButtonAct, + buttonMenu, + handleConfirm, + handleRollBack, + } = props + + const eavesProps = { pitch, setPitch, eavesOffset, setEavesOffset } + const gableProps = { gableOffset, setGableOffset } + const wallProps = { sleeveOffset, setSleeveOffset, hasSleeve, setHasSleeve } + const hipAndGableProps = { pitch, setPitch, eavesOffset, setEavesOffset, hipAndGableWidth, setHipAndGableWidth } + const jerkinheadProps = { gableOffset, setGableOffset, jerkinHeadWidth, setJerkinHeadWidth, jerkinHeadPitch, setJerkinHeadPitch } + const shedProps = { shedWidth, setShedWidth } + const { getMessage } = useMessage() - 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') }, - ] + return (
- {buttonMenu.map((item) => ( - ))}
- {buttonAct === 1 && } - {buttonAct === 2 && } - {buttonAct === 3 && } - {buttonAct === 4 && } - {buttonAct === 5 && } - {buttonAct === 6 && } + {buttonAct === 1 && } + {buttonAct === 2 && } + {buttonAct === 3 && } + {buttonAct === 4 && } + {buttonAct === 5 && } + {buttonAct === 6 && }
- - + +
) diff --git a/src/components/floor-plan/modal/roofShape/type/option/Eaves.jsx b/src/components/floor-plan/modal/roofShape/type/option/Eaves.jsx index 303dad55..8d061a7b 100644 --- a/src/components/floor-plan/modal/roofShape/type/option/Eaves.jsx +++ b/src/components/floor-plan/modal/roofShape/type/option/Eaves.jsx @@ -1,6 +1,7 @@ import { useMessage } from '@/hooks/useMessage' +import { onlyNumberInputChange, onlyNumberWithDotInputChange } from '@/util/input-utils' -export default function Eaves() { +export default function Eaves({ pitch, setPitch, eavesOffset, setEavesOffset }) { const { getMessage } = useMessage() return ( <> @@ -9,7 +10,7 @@ export default function Eaves() { {getMessage('slope')}
- + onlyNumberWithDotInputChange(e, setPitch)} />
{getMessage('size')} @@ -18,7 +19,7 @@ export default function Eaves() { {getMessage('eaves.offset')}
- + onlyNumberInputChange(e, setEavesOffset)} />
mm diff --git a/src/components/floor-plan/modal/roofShape/type/option/Gable.jsx b/src/components/floor-plan/modal/roofShape/type/option/Gable.jsx index 63092550..08e503d2 100644 --- a/src/components/floor-plan/modal/roofShape/type/option/Gable.jsx +++ b/src/components/floor-plan/modal/roofShape/type/option/Gable.jsx @@ -1,13 +1,16 @@ import { useMessage } from '@/hooks/useMessage' +import { useEffect } from 'react' +import { onlyNumberInputChange } from '@/util/input-utils' -export default function Gable() { +export default function Gable({ gableOffset, setGableOffset }) { const { getMessage } = useMessage() + return ( <>
{getMessage('gable.offset')}
- + onlyNumberInputChange(e, setGableOffset)} />
mm
diff --git a/src/components/floor-plan/modal/roofShape/type/option/HipAndGable.jsx b/src/components/floor-plan/modal/roofShape/type/option/HipAndGable.jsx index ed2e1b60..ce4a57cc 100644 --- a/src/components/floor-plan/modal/roofShape/type/option/HipAndGable.jsx +++ b/src/components/floor-plan/modal/roofShape/type/option/HipAndGable.jsx @@ -1,6 +1,7 @@ import { useMessage } from '@/hooks/useMessage' +import { onlyNumberInputChange, onlyNumberWithDotInputChange } from '@/util/input-utils' -export default function HipAndGable() { +export default function HipAndGable({ pitch, setPitch, eavesOffset, setEavesOffset, hipAndGableWidth, setHipAndGableWidth }) { const { getMessage } = useMessage() return ( <> @@ -9,7 +10,7 @@ export default function HipAndGable() { {getMessage('slope')}
- + onlyNumberWithDotInputChange(e, setPitch)} />
{getMessage('size')} @@ -18,16 +19,21 @@ export default function HipAndGable() { {getMessage('eaves.offset')}
- + onlyNumberInputChange(e, setEavesOffset)} />
mm
- {getMessage('gable.offset')} + {getMessage('hipandgable.width')}
- + onlyNumberInputChange(e, setHipAndGableWidth)} + />
mm
diff --git a/src/components/floor-plan/modal/roofShape/type/option/Jerkinhead.jsx b/src/components/floor-plan/modal/roofShape/type/option/Jerkinhead.jsx index d5737470..be846e94 100644 --- a/src/components/floor-plan/modal/roofShape/type/option/Jerkinhead.jsx +++ b/src/components/floor-plan/modal/roofShape/type/option/Jerkinhead.jsx @@ -1,6 +1,7 @@ import { useMessage } from '@/hooks/useMessage' +import { onlyNumberInputChange, onlyNumberWithDotInputChange } from '@/util/input-utils' -export default function Jerkinhead() { +export default function Jerkinhead({ gableOffset, setGableOffset, jerkinHeadWidth, setJerkinHeadWidth, jerkinHeadPitch, setJerkinHeadPitch }) { const { getMessage } = useMessage() return ( <> @@ -9,7 +10,7 @@ export default function Jerkinhead() { {getMessage('gable.offset')}
- + onlyNumberInputChange(e, setGableOffset)} />
mm @@ -18,7 +19,7 @@ export default function Jerkinhead() { {getMessage('jerkinhead.width')}
- + onlyNumberInputChange(e, setJerkinHeadWidth)} />
mm @@ -27,7 +28,12 @@ export default function Jerkinhead() { {getMessage('jerkinhead.slope')}
- + onlyNumberWithDotInputChange(e, setJerkinHeadPitch)} + />
{getMessage('size')} diff --git a/src/components/floor-plan/modal/roofShape/type/option/Shed.jsx b/src/components/floor-plan/modal/roofShape/type/option/Shed.jsx index c4fd4333..40ccdbef 100644 --- a/src/components/floor-plan/modal/roofShape/type/option/Shed.jsx +++ b/src/components/floor-plan/modal/roofShape/type/option/Shed.jsx @@ -1,13 +1,14 @@ import { useMessage } from '@/hooks/useMessage' +import { onlyNumberInputChange } from '@/util/input-utils' -export default function Shed() { +export default function Shed({ shedWidth, setShedWidth }) { const { getMessage } = useMessage() return ( <>
{getMessage('shed.width')}
- + onlyNumberInputChange(e, setShedWidth)} />
mm
diff --git a/src/components/floor-plan/modal/roofShape/type/option/Wall.jsx b/src/components/floor-plan/modal/roofShape/type/option/Wall.jsx index 6b716892..c7b04b2d 100644 --- a/src/components/floor-plan/modal/roofShape/type/option/Wall.jsx +++ b/src/components/floor-plan/modal/roofShape/type/option/Wall.jsx @@ -1,8 +1,8 @@ import { useState } from 'react' import { useMessage } from '@/hooks/useMessage' +import { onlyNumberInputChange } from '@/util/input-utils' -export default function Wall() { - const [hasSleeve, setHasSleeve] = useState('0') +export default function Wall({ sleeveOffset, setSleeveOffset, hasSleeve, setHasSleeve }) { const { getMessage } = useMessage() return ( <> @@ -26,7 +26,13 @@ export default function Wall() {
- + onlyNumberInputChange(e, setSleeveOffset)} + readOnly={hasSleeve === '0'} + />
mm
diff --git a/src/hooks/roofcover/useOuterLineWall.js b/src/hooks/roofcover/useOuterLineWall.js index 130593a0..72fdf91f 100644 --- a/src/hooks/roofcover/useOuterLineWall.js +++ b/src/hooks/roofcover/useOuterLineWall.js @@ -6,6 +6,7 @@ import { adsorptionPointModeState, adsorptionRangeState, canvasState, + currentCanvasPlanState, dotLineIntervalSelector, verticalHorizontalModeState, } from '@/store/canvasAtom' @@ -43,7 +44,7 @@ export function useOuterLineWall() { const adsorptionPointMode = useRecoilValue(adsorptionPointModeState) const adsorptionRange = useRecoilValue(adsorptionRangeState) const interval = useRecoilValue(dotLineIntervalSelector) // 가로 세로 간격 - + const currentCanvasPlan = useRecoilValue(currentCanvasPlanState) const length1Ref = useRef(null) const length2Ref = useRef(null) const angle1Ref = useRef(null) @@ -73,14 +74,6 @@ export function useOuterLineWall() { return } - if (points.length === 0) { - // 만약 포인트가 없다면 모든 라인과 텍스트를 삭제 후 outerLines에서 point를 뽑아 points에 넣어준다. - const lengthTxts = canvas?.getObjects().filter((obj) => obj.name === 'lengthTxt') - lengthTxts.forEach((txt) => { - canvas?.remove(txt) - }) - } - addCanvasMouseEventListener('mouse:down', mouseDown) clear() }, [verticalHorizontalMode, points, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, interval, tempGridMode]) @@ -98,6 +91,18 @@ export function useOuterLineWall() { addDocumentEventListener('keydown', document, keydown[type]) }, [type]) + useEffect(() => { + const outerLinePoints = canvas?.getObjects().filter((obj) => obj.name === 'outerLinePoint') + const newPoints = [] + if (points.length === 0 && outerLinePoints.length > 0) { + outerLinePoints.forEach((point) => { + newPoints.push({ x: point.left, y: point.top }) + }) + + setPoints(newPoints) + } + }, []) + const clear = () => { setLength1(0) setLength2(0) @@ -186,6 +191,21 @@ export function useOuterLineWall() { canvas?.add(point) } else { setOuterLineFix(false) + canvas + .getObjects() + .filter((obj) => obj.name === 'outerLinePoint') + .forEach((obj) => { + canvas.remove(obj) + }) + points.forEach((point, idx) => { + const circle = new fabric.Circle({ + left: point.x, + top: point.y, + visible: false, + name: 'outerLinePoint', + }) + canvas.add(circle) + }) points.forEach((point, idx) => { if (idx === 0) { return @@ -272,6 +292,10 @@ export function useOuterLineWall() { idx: idx, selectable: true, name: 'outerLine', + x1: point1.x, + y1: point1.y, + x2: point2.x, + y2: point2.y, }) } diff --git a/src/hooks/roofcover/usePropertiesSetting.js b/src/hooks/roofcover/usePropertiesSetting.js index d478a1bc..00ad3890 100644 --- a/src/hooks/roofcover/usePropertiesSetting.js +++ b/src/hooks/roofcover/usePropertiesSetting.js @@ -1,10 +1,11 @@ import { useEffect, useRef } from 'react' import { LINE_TYPE } from '@/common/common' -import { useRecoilValue } from 'recoil' +import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil' import { canvasState, currentObjectState } from '@/store/canvasAtom' import { useMode } from '@/hooks/useMode' import { usePolygon } from '@/hooks/usePolygon' import { useLine } from '@/hooks/useLine' +import { outerLinePointsState } from '@/store/outerLineAtom' export function usePropertiesSetting() { const canvas = useRecoilValue(canvasState) @@ -12,9 +13,10 @@ export function usePropertiesSetting() { const currentObject = useRecoilValue(currentObjectState) const { drawRoofPolygon } = useMode() + const setPoints = useResetRecoilState(outerLinePointsState) const { addPolygonByLines } = usePolygon() - const { removeLine } = useLine() + const { removeLine, hideLine } = useLine() useEffect(() => { if (!currentObject) { @@ -125,7 +127,8 @@ export function usePropertiesSetting() { stroke: '#000000', strokeWidth: 4, }) - removeLine(line) + + hideLine(hideLine) }) const wall = addPolygonByLines(lines, { name: 'WallLine', fill: 'transparent', stroke: 'black' }) @@ -133,7 +136,7 @@ export function usePropertiesSetting() { wall.lines = [...lines] drawRoofPolygon(wall) - + setPoints([]) canvas.renderAll() } @@ -153,6 +156,7 @@ export function usePropertiesSetting() { }) canvas.renderAll() + setPoints([]) fn(false) } diff --git a/src/hooks/roofcover/useRoofShapeSetting.js b/src/hooks/roofcover/useRoofShapeSetting.js new file mode 100644 index 00000000..492e52e8 --- /dev/null +++ b/src/hooks/roofcover/useRoofShapeSetting.js @@ -0,0 +1,496 @@ +import { useEffect, useRef, useState } from 'react' +import { useMessage } from '@/hooks/useMessage' +import { useRecoilValue } from 'recoil' +import { canvasState, currentObjectState } from '@/store/canvasAtom' +import { LINE_TYPE } from '@/common/common' +import { usePolygon } from '@/hooks/usePolygon' +import { useMode } from '@/hooks/useMode' +import { useLine } from '@/hooks/useLine' + +export function useRoofShapeSetting() { + const [shapeNum, setShapeNum] = useState(1) + const [buttonAct, setButtonAct] = useState(1) + const { getMessage } = useMessage() + const canvas = useRecoilValue(canvasState) + const { addPolygonByLines } = usePolygon() + const [pitch, setPitch] = useState(4) + const [eavesOffset, setEavesOffset] = useState(500) // 처마출폭 + const [gableOffset, setGableOffset] = useState(300) // 케라바출폭 + const [sleeveOffset, setSleeveOffset] = useState(300) // 소매출폭 + const [jerkinHeadWidth, setJerkinHeadWidth] = useState(800) // 반절처 폭 + const [jerkinHeadPitch, setJerkinHeadPitch] = useState(4.5) // 반절처 경사 + const [hipAndGableWidth, setHipAndGableWidth] = useState(800) // 팔작지붕 폭 + const [shedWidth, setShedWidth] = useState(300) // 한쪽흐름 폭 + const [hasSleeve, setHasSleeve] = useState('0') + const currentObject = useRecoilValue(currentObjectState) + const { drawRoofPolygon } = useMode() + const { hideLine, showLine } = useLine() + + const history = useRef([]) + + useEffect(() => { + const wallLine = canvas.getObjects().find((obj) => obj.name === 'wallLine') + canvas?.remove(wallLine) + + const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') + outerLines.forEach((line) => { + showLine(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 === 'wallLine')) + const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') + outerLines.forEach((line) => { + showLine(line) + line.bringToFront() + }) + + canvas?.renderAll() + } + setPitch(4) + setEavesOffset(500) + setGableOffset(300) + setSleeveOffset(300) + setJerkinHeadWidth(800) + setJerkinHeadPitch(4.5) + 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 = (fn) => { + //기존 wallLine 삭제 + + let outerLines + canvas?.remove(canvas.getObjects().find((obj) => obj.name === 'wallLine')) + canvas?.remove(canvas.getObjects().find((obj) => obj.name === 'roofBase')) + + 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') + + outerLines.forEach((line) => { + setWestAndEastRoof(line) + if (line.direction === 'bottom') { + line.attributes = { + offset: eavesOffset / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.EAVES, + } + } + + if (line.direction === 'top') { + line.attributes = { + offset: shedWidth / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.SHED, + } + } + + hideLine(line) + }) + break + } + case 6: { + initLineSetting() + outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') + + outerLines.forEach((line) => { + setWestAndEastRoof(line) + if (line.direction === 'top') { + line.attributes = { + offset: eavesOffset / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.EAVES, + } + } + + if (line.direction === 'bottom') { + line.attributes = { + offset: shedWidth / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.SHED, + } + } + + hideLine(line) + }) + break + } + case 7: { + initLineSetting() + outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') + + outerLines.forEach((line) => { + setWestAndEastRoof(line) + if (line.direction === 'left') { + line.attributes = { + offset: eavesOffset / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.EAVES, + } + } + + if (line.direction === 'right') { + line.attributes = { + offset: shedWidth / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.SHED, + } + } + + hideLine(line) + }) + break + } + case 8: { + initLineSetting() + outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') + + outerLines.forEach((line) => { + setWestAndEastRoof(line) + if (line.direction === 'right') { + line.attributes = { + offset: eavesOffset / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.EAVES, + } + } + + if (line.direction === 'left') { + line.attributes = { + offset: shedWidth / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.SHED, + } + } + + hideLine(line) + }) + break + } + } + + const polygon = addPolygonByLines(outerLines, { name: 'wallLine' }) + polygon.lines = [...outerLines] + + drawRoofPolygon(polygon) + + canvas?.renderAll() + + console.log(canvas.getObjects()) + + fn && fn(false) + } + + 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 + } + }) + }) + + // 첫번째 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: pitch, + type: LINE_TYPE.WALLLINE.EAVES, + } + hideLine(line) + }) + + return outerLines + } + + // 패턴 A : 가로선이 모두 케라바 + const saveAPattern = () => { + const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') + + outerLines + .filter((line) => line.direction === 'left' || line.direction === 'right') + .forEach((line) => { + line.attributes = { + offset: gableOffset / 10, + type: LINE_TYPE.WALLLINE.GABLE, + } + }) + + outerLines + .filter((line) => line.direction === 'top' || line.direction === 'bottom') + .forEach((line) => { + line.attributes = { + offset: eavesOffset / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.EAVES, + } + }) + + return outerLines + } + + // 패턴 B : 세로선이 모두 케라바 + const saveBPattern = () => { + const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') + + outerLines + .filter((line) => line.direction === 'left' || line.direction === 'right') + .forEach((line) => { + line.attributes = { + offset: eavesOffset / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.EAVES, + } + }) + + outerLines + .filter((line) => line.direction === 'top' || line.direction === 'bottom') + .forEach((line) => { + line.attributes = { + offset: gableOffset / 10, + type: LINE_TYPE.WALLLINE.GABLE, + } + }) + + return outerLines + } + + // 변별로 설정 팝업 내 적용 + const handleConfirm = () => { + const selectedLine = canvas?.getActiveObject() + if (!selectedLine) { + return + } + + let attributes + switch (buttonAct) { + case 1: { + // 처마 + attributes = { + type: LINE_TYPE.WALLLINE.EAVES, + pitch: pitch, + offset: eavesOffset / 10, + } + break + } + case 2: { + // 케라바 + attributes = { + type: LINE_TYPE.WALLLINE.GABLE, + offset: gableOffset / 10, + } + break + } + case 3: { + // 벽 + attributes = { + type: LINE_TYPE.WALLLINE.WALL, + offset: hasSleeve === '0' ? 0 : sleeveOffset / 10, + } + break + } + case 4: { + // 팔작지붕 + attributes = { + type: LINE_TYPE.WALLLINE.HIPANDGABLE, + pitch: pitch, + offset: eavesOffset / 10, + width: hipAndGableWidth / 10, + } + break + } + case 5: { + // 반절처 + attributes = { + type: LINE_TYPE.WALLLINE.JERKINHEAD, + offset: gableOffset / 10, + width: jerkinHeadWidth / 10, + pitch: jerkinHeadPitch, + } + break + } + case 6: { + // 한쪽흐름 + attributes = { + type: LINE_TYPE.WALLLINE.SHED, + offset: shedWidth / 10, + } + break + } + } + selectedLine.attributes = attributes + history.current.push(selectedLine) + 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() + + 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, + } +} diff --git a/src/hooks/useLine.js b/src/hooks/useLine.js index b6c8a532..f2941e33 100644 --- a/src/hooks/useLine.js +++ b/src/hooks/useLine.js @@ -14,26 +14,38 @@ export const useLine = () => { fontFamily: fontFamily, }) + if (line.length === 0) { + return null + } + canvas?.add(line) return line } - const addLineText = (line, length = getLengthByLine(line)) => { - removeLineText(line) - - const lengthTxt = isNaN(Number(length)) ? length : length.toFixed(0) - - const text = new fabric.Text(lengthTxt, { - left: (line.x2 + line.x1) / 2, - top: (line.y2 + line.y1) / 2, - parent: line, - name: 'lengthTxt', - fontSize: fontSize, - fontFamily: fontFamily, + const hideLine = (line) => { + line.set({ + visible: false, }) + canvas + ?.getObjects() + .find((obj) => obj.parent === line) + .set({ + visible: false, + }) + canvas?.renderAll() + } - canvas?.add(text) - return text + const showLine = (line) => { + line.set({ + visible: true, + }) + canvas + ?.getObjects() + .find((obj) => obj.parent === line) + .set({ + visible: true, + }) + canvas?.renderAll() } const removeLine = (line) => { @@ -62,5 +74,7 @@ export const useLine = () => { return { addLine, removeLine, + hideLine, + showLine, } } diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index fedbb3be..c719ba24 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -47,6 +47,11 @@ export function usePlan() { 'minY', 'x', 'y', + 'x1', + 'x2', + 'y1', + 'y2', + 'attributes', 'stickeyPoint', ]) diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index 13b12fe1..2d981933 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -12,6 +12,8 @@ export const usePolygon = () => { const addPolygon = (points, options) => { const polygon = new QPolygon(points, { ...options, + fill: options.fill || 'transparent', + stroke: options.stroke || '#000000', fontSize: fontSize, fontFamily: fontFamily, selectable: true, diff --git a/src/locales/ja.json b/src/locales/ja.json index 71c6fb8d..48937cc0 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -303,6 +303,7 @@ "gable": "ケラバ", "wall": "壁", "hipandgable": "八作屋根", + "hipandgable.width": "八作屋根 出幅", "jerkinhead": "半折", "shed": "片側の流れ", "apply": "適用", diff --git a/src/locales/ko.json b/src/locales/ko.json index 572c1eef..c586d95f 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -34,7 +34,7 @@ "modal.roof.shape.setting": "지붕형상 설정", "modal.roof.shape.setting.ridge": "용마루", "modal.roof.shape.setting.patten.a": "A 패턴", - "modal.roof.shape.setting.patten.b": "A 패턴", + "modal.roof.shape.setting.patten.b": "B 패턴", "modal.roof.shape.setting.side": "변별로 설정", "plan.menu.roof.cover": "지붕덮개", "plan.menu.roof.cover.outline.drawing": "외벽선 그리기", @@ -305,6 +305,7 @@ "gable": "케라바", "wall": "벽", "hipandgable": "팔작지붕", + "hipandgable.width": "팔작지붕의 폭", "jerkinhead": "반절처", "shed": "한쪽흐름", "apply": "적용", diff --git a/src/util/input-utils.js b/src/util/input-utils.js index f674e6cd..18f93425 100644 --- a/src/util/input-utils.js +++ b/src/util/input-utils.js @@ -1,6 +1,6 @@ // 숫자만 입력 가능한 input onChange 함수 export const onlyNumberInputChange = (e, callback) => { - let value = e.target.value.replace(/^0+/, '') + let value = e.target.value value = value.replace(/[^-0-9]/g, '') callback(value, e) } diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index a7bcb0e2..6605e3b3 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -1197,6 +1197,7 @@ export const drawHippedRoof = (polygon, chon) => { alert('대각선이 존재합니다.') return } + drawRidgeRoof(polygon, chon) drawHips(polygon) connectLinePoint(polygon)