배치면 추가
This commit is contained in:
parent
8d0e2b59a0
commit
e172b2cd33
@ -8,6 +8,7 @@ import Diagonal from '@/components/floor-plan/modal/lineTypes/Diagonal'
|
|||||||
import { useOuterLineWall } from '@/hooks/roofcover/useOuterLineWall'
|
import { useOuterLineWall } from '@/hooks/roofcover/useOuterLineWall'
|
||||||
import { OUTER_LINE_TYPE } from '@/store/outerLineAtom'
|
import { OUTER_LINE_TYPE } from '@/store/outerLineAtom'
|
||||||
import OuterLineWall from '@/components/floor-plan/modal/lineTypes/OuterLineWall'
|
import OuterLineWall from '@/components/floor-plan/modal/lineTypes/OuterLineWall'
|
||||||
|
import { usePlacementShapeDrawing } from '@/hooks/surface/usePlacementShapeDrawing'
|
||||||
|
|
||||||
export default function PlacementShapeDrawing({ setShowPlaceShapeDrawingModal }) {
|
export default function PlacementShapeDrawing({ setShowPlaceShapeDrawingModal }) {
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
@ -45,7 +46,7 @@ export default function PlacementShapeDrawing({ setShowPlaceShapeDrawingModal })
|
|||||||
outerLineDiagonalLengthRef,
|
outerLineDiagonalLengthRef,
|
||||||
handleRollback,
|
handleRollback,
|
||||||
handleFix,
|
handleFix,
|
||||||
} = useOuterLineWall()
|
} = usePlacementShapeDrawing(setShowPlaceShapeDrawingModal)
|
||||||
|
|
||||||
const outerLineProps = {
|
const outerLineProps = {
|
||||||
length1,
|
length1,
|
||||||
@ -145,8 +146,12 @@ export default function PlacementShapeDrawing({ setShowPlaceShapeDrawingModal })
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid-btn-wrap">
|
<div className="grid-btn-wrap">
|
||||||
<button className="btn-frame modal mr5">{getMessage('modal.cover.outline.rollback')}</button>
|
<button className="btn-frame modal mr5" onClick={handleRollback}>
|
||||||
<button className="btn-frame modal act">{getMessage('modal.cover.outline.fix')}</button>
|
{getMessage('modal.cover.outline.rollback')}
|
||||||
|
</button>
|
||||||
|
<button className="btn-frame modal act" onClick={handleFix}>
|
||||||
|
{getMessage('modal.cover.outline.fix')}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
825
src/hooks/surface/usePlacementShapeDrawing.js
Normal file
825
src/hooks/surface/usePlacementShapeDrawing.js
Normal file
@ -0,0 +1,825 @@
|
|||||||
|
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
|
||||||
|
import {
|
||||||
|
adsorptionPointAddModeState,
|
||||||
|
adsorptionPointModeState,
|
||||||
|
adsorptionRangeState,
|
||||||
|
canvasState,
|
||||||
|
dotLineIntervalSelector,
|
||||||
|
verticalHorizontalModeState,
|
||||||
|
} from '@/store/canvasAtom'
|
||||||
|
import { useEvent } from '@/hooks/useEvent'
|
||||||
|
import { useMouse } from '@/hooks/useMouse'
|
||||||
|
import { useLine } from '@/hooks/useLine'
|
||||||
|
import { useTempGrid } from '@/hooks/useTempGrid'
|
||||||
|
import { useEffect, useRef } from 'react'
|
||||||
|
import { distanceBetweenPoints, setSurfaceShapePattern } from '@/util/canvas-util'
|
||||||
|
import { fabric } from 'fabric'
|
||||||
|
import { calculateAngle } from '@/util/qpolygon-utils'
|
||||||
|
import {
|
||||||
|
placementShapeDrawingAngle1State,
|
||||||
|
placementShapeDrawingAngle2State,
|
||||||
|
placementShapeDrawingArrow1State,
|
||||||
|
placementShapeDrawingArrow2State,
|
||||||
|
placementShapeDrawingDiagonalState,
|
||||||
|
placementShapeDrawingFixState,
|
||||||
|
placementShapeDrawingLength1State,
|
||||||
|
placementShapeDrawingLength2State,
|
||||||
|
placementShapeDrawingPointsState,
|
||||||
|
placementShapeDrawingTypeState,
|
||||||
|
} from '@/store/placementShapeDrawingAtom'
|
||||||
|
import { usePolygon } from '@/hooks/usePolygon'
|
||||||
|
import { POLYGON_TYPE } from '@/common/common'
|
||||||
|
|
||||||
|
// 면형상 배치
|
||||||
|
export function usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) {
|
||||||
|
const canvas = useRecoilValue(canvasState)
|
||||||
|
const { addCanvasMouseEventListener, addDocumentEventListener, removeAllMouseEventListeners, removeAllDocumentEventListeners, removeMouseEvent } =
|
||||||
|
useEvent()
|
||||||
|
const { getIntersectMousePoint } = useMouse()
|
||||||
|
const { addLine, removeLine } = useLine()
|
||||||
|
const { addPolygonByLines } = usePolygon()
|
||||||
|
const { tempGridMode } = useTempGrid()
|
||||||
|
|
||||||
|
const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState)
|
||||||
|
const adsorptionPointAddMode = useRecoilValue(adsorptionPointAddModeState)
|
||||||
|
const adsorptionPointMode = useRecoilValue(adsorptionPointModeState)
|
||||||
|
const adsorptionRange = useRecoilValue(adsorptionRangeState)
|
||||||
|
const interval = useRecoilValue(dotLineIntervalSelector) // 가로 세로 간격
|
||||||
|
|
||||||
|
const length1Ref = useRef(null)
|
||||||
|
const length2Ref = useRef(null)
|
||||||
|
const angle1Ref = useRef(null)
|
||||||
|
const angle2Ref = useRef(null)
|
||||||
|
const [length1, setLength1] = useRecoilState(placementShapeDrawingLength1State)
|
||||||
|
const [length2, setLength2] = useRecoilState(placementShapeDrawingLength2State)
|
||||||
|
const [arrow1, setArrow1] = useRecoilState(placementShapeDrawingArrow1State)
|
||||||
|
const [arrow2, setArrow2] = useRecoilState(placementShapeDrawingArrow2State)
|
||||||
|
const [points, setPoints] = useRecoilState(placementShapeDrawingPointsState)
|
||||||
|
const [type, setType] = useRecoilState(placementShapeDrawingTypeState)
|
||||||
|
const [angle1, setAngle1] = useRecoilState(placementShapeDrawingAngle1State)
|
||||||
|
const [angle2, setAngle2] = useRecoilState(placementShapeDrawingAngle2State)
|
||||||
|
const [outerLineDiagonalLength, setOuterLineDiagonalLength] = useRecoilState(placementShapeDrawingDiagonalState)
|
||||||
|
const setOuterLineFix = useSetRecoilState(placementShapeDrawingFixState)
|
||||||
|
const arrow1Ref = useRef(arrow1)
|
||||||
|
const arrow2Ref = useRef(arrow2)
|
||||||
|
|
||||||
|
const outerLineDiagonalLengthRef = useRef(null)
|
||||||
|
|
||||||
|
const isFix = useRef(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (adsorptionPointAddMode || tempGridMode) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
addCanvasMouseEventListener('mouse:down', mouseDown)
|
||||||
|
clear()
|
||||||
|
}, [verticalHorizontalMode, points, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, interval, tempGridMode])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
arrow1Ref.current = arrow1
|
||||||
|
}, [arrow1])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
arrow2Ref.current = arrow2
|
||||||
|
}, [arrow2])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
clear()
|
||||||
|
addDocumentEventListener('keydown', document, keydown[type])
|
||||||
|
}, [type])
|
||||||
|
|
||||||
|
const clear = () => {
|
||||||
|
setLength1(0)
|
||||||
|
setLength2(0)
|
||||||
|
|
||||||
|
setArrow1('')
|
||||||
|
setArrow2('')
|
||||||
|
|
||||||
|
setAngle1(0)
|
||||||
|
setAngle2(0)
|
||||||
|
|
||||||
|
setOuterLineDiagonalLength(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const mouseDown = (e) => {
|
||||||
|
let pointer = getIntersectMousePoint(e)
|
||||||
|
|
||||||
|
if (points.length === 0) {
|
||||||
|
setPoints((prev) => [...prev, pointer])
|
||||||
|
} else {
|
||||||
|
const lastPoint = points[points.length - 1]
|
||||||
|
let newPoint = { x: pointer.x, y: pointer.y }
|
||||||
|
const length = distanceBetweenPoints(lastPoint, newPoint)
|
||||||
|
if (verticalHorizontalMode) {
|
||||||
|
const vector = {
|
||||||
|
x: pointer.x - points[points.length - 1].x,
|
||||||
|
y: pointer.y - points[points.length - 1].y,
|
||||||
|
}
|
||||||
|
const slope = Math.abs(vector.y / vector.x) // 기울기 계산
|
||||||
|
|
||||||
|
let scaledVector
|
||||||
|
if (slope >= 1) {
|
||||||
|
// 기울기가 1 이상이면 x축 방향으로 그림
|
||||||
|
scaledVector = {
|
||||||
|
x: 0,
|
||||||
|
y: vector.y >= 0 ? Number(length) : -Number(length),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 기울기가 1 미만이면 y축 방향으로 그림
|
||||||
|
scaledVector = {
|
||||||
|
x: vector.x >= 0 ? Number(length) : -Number(length),
|
||||||
|
y: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const verticalLength = scaledVector.y
|
||||||
|
const horizontalLength = scaledVector.x
|
||||||
|
|
||||||
|
newPoint = {
|
||||||
|
x: lastPoint.x + horizontalLength,
|
||||||
|
y: lastPoint.y + verticalLength,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setPoints((prev) => [...prev, newPoint])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
canvas
|
||||||
|
?.getObjects()
|
||||||
|
.filter((obj) => obj.name === 'placementShapeDrawingLine' || obj.name === 'helpGuideLine')
|
||||||
|
.forEach((obj) => {
|
||||||
|
removeLine(obj)
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas?.remove(canvas?.getObjects().find((obj) => obj.name === 'placementShapeDrawingStartPoint'))
|
||||||
|
|
||||||
|
if (points.length === 0) {
|
||||||
|
setOuterLineFix(true)
|
||||||
|
removeAllDocumentEventListeners()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
addDocumentEventListener('keydown', document, keydown[type])
|
||||||
|
|
||||||
|
if (points.length === 1) {
|
||||||
|
const point = new fabric.Circle({
|
||||||
|
radius: 5,
|
||||||
|
fill: 'transparent',
|
||||||
|
stroke: 'red',
|
||||||
|
left: points[0].x - 5,
|
||||||
|
top: points[0].y - 5,
|
||||||
|
selectable: false,
|
||||||
|
name: 'placementShapeDrawingStartPoint',
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas?.add(point)
|
||||||
|
} else {
|
||||||
|
setOuterLineFix(false)
|
||||||
|
canvas
|
||||||
|
.getObjects()
|
||||||
|
.filter((obj) => obj.name === 'placementShapeDrawingPoint')
|
||||||
|
.forEach((obj) => {
|
||||||
|
canvas.remove(obj)
|
||||||
|
})
|
||||||
|
points.forEach((point, idx) => {
|
||||||
|
const circle = new fabric.Circle({
|
||||||
|
left: point.x,
|
||||||
|
top: point.y,
|
||||||
|
visible: false,
|
||||||
|
name: 'placementShapeDrawingPoint',
|
||||||
|
})
|
||||||
|
canvas.add(circle)
|
||||||
|
})
|
||||||
|
points.forEach((point, idx) => {
|
||||||
|
if (idx === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
drawLine(points[idx - 1], point, idx)
|
||||||
|
})
|
||||||
|
|
||||||
|
const lastPoint = points[points.length - 1]
|
||||||
|
const firstPoint = points[0]
|
||||||
|
|
||||||
|
if (isFix.current) {
|
||||||
|
removeAllMouseEventListeners()
|
||||||
|
removeAllDocumentEventListeners()
|
||||||
|
|
||||||
|
const lines = canvas?.getObjects().filter((obj) => obj.name === 'placementShapeDrawingLine')
|
||||||
|
const roof = addPolygonByLines(lines, {
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 3,
|
||||||
|
selectable: true,
|
||||||
|
name: POLYGON_TYPE.ROOF,
|
||||||
|
})
|
||||||
|
|
||||||
|
setSurfaceShapePattern(roof)
|
||||||
|
|
||||||
|
lines.forEach((line) => {
|
||||||
|
removeLine(line)
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas?.renderAll()
|
||||||
|
setShowPlaceShapeDrawingModal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (points.length < 3) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if (lastPoint.x === firstPoint.x && lastPoint.y === firstPoint.y) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastPoint.x === firstPoint.x || lastPoint.y === firstPoint.y) {
|
||||||
|
let isAllRightAngle = true
|
||||||
|
|
||||||
|
const firstPoint = points[0]
|
||||||
|
|
||||||
|
points.forEach((point, idx) => {
|
||||||
|
if (idx === 0 || !isAllRightAngle) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const angle = calculateAngle(point, firstPoint)
|
||||||
|
if (angle % 90 !== 0) {
|
||||||
|
isAllRightAngle = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (isAllRightAngle) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const line = new QLine([lastPoint.x, lastPoint.y, firstPoint.x, firstPoint.y], {
|
||||||
|
stroke: 'grey',
|
||||||
|
strokeWidth: 1,
|
||||||
|
selectable: false,
|
||||||
|
name: 'helpGuideLine',
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas?.add(line)
|
||||||
|
addLineText(line)
|
||||||
|
} else {
|
||||||
|
const guideLine1 = new QLine([lastPoint.x, lastPoint.y, lastPoint.x, firstPoint.y], {
|
||||||
|
stroke: 'grey',
|
||||||
|
strokeWidth: 1,
|
||||||
|
strokeDashArray: [1, 1, 1],
|
||||||
|
name: 'helpGuideLine',
|
||||||
|
})
|
||||||
|
|
||||||
|
const guideLine2 = new QLine([guideLine1.x2, guideLine1.y2, firstPoint.x, firstPoint.y], {
|
||||||
|
stroke: 'grey',
|
||||||
|
strokeWidth: 1,
|
||||||
|
strokeDashArray: [1, 1, 1],
|
||||||
|
name: 'helpGuideLine',
|
||||||
|
})
|
||||||
|
if (guideLine1.length > 0) {
|
||||||
|
canvas?.add(guideLine1)
|
||||||
|
addLineText(guideLine1)
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas?.add(guideLine2)
|
||||||
|
|
||||||
|
addLineText(guideLine2)
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}, [points])
|
||||||
|
|
||||||
|
const drawLine = (point1, point2, idx) => {
|
||||||
|
addLine([point1.x, point1.y, point2.x, point2.y], {
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 3,
|
||||||
|
idx: idx,
|
||||||
|
selectable: true,
|
||||||
|
name: 'placementShapeDrawingLine',
|
||||||
|
x1: point1.x,
|
||||||
|
y1: point1.y,
|
||||||
|
x2: point2.x,
|
||||||
|
y2: point2.y,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 직각 완료될 경우 확인
|
||||||
|
const checkRightAngle = (direction) => {
|
||||||
|
const activeElem = document.activeElement
|
||||||
|
|
||||||
|
const canDirection =
|
||||||
|
direction === '↓' || direction === '↑'
|
||||||
|
? arrow1Ref.current === '←' || arrow1Ref.current === '→'
|
||||||
|
: arrow1Ref.current === '↓' || arrow1Ref.current === '↑'
|
||||||
|
|
||||||
|
if (activeElem === length1Ref.current || activeElem === angle1Ref.current) {
|
||||||
|
setArrow1(direction)
|
||||||
|
arrow1Ref.current = direction
|
||||||
|
length2Ref.current.focus()
|
||||||
|
} else if (activeElem === length2Ref.current || activeElem === angle2Ref.current) {
|
||||||
|
if (!canDirection) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setArrow2(direction)
|
||||||
|
arrow2Ref.current = direction
|
||||||
|
}
|
||||||
|
|
||||||
|
const length1Num = Number(length1Ref.current.value) / 10
|
||||||
|
const length2Num = Number(length2Ref.current.value) / 10
|
||||||
|
|
||||||
|
if (points.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length1Num === 0 || length2Num === 0 || arrow1Ref.current === '' || arrow2Ref.current === '') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arrow1Ref.current === '↓' && arrow2Ref.current === '→') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x + length2Num, y: prev[prev.length - 1].y + length1Num }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Ref.current === '↓' && arrow2Ref.current === '←') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x - length2Num, y: prev[prev.length - 1].y + length1Num }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Ref.current === '↑' && arrow2Ref.current === '→') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x + length2Num, y: prev[prev.length - 1].y - length1Num }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Ref.current === '↑' && arrow2Ref.current === '←') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x - length2Num, y: prev[prev.length - 1].y - length1Num }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Ref.current === '→' && arrow2Ref.current === '↓') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x + length1Num, y: prev[prev.length - 1].y + length2Num }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Ref.current === '→' && arrow2Ref.current === '↑') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x + length1Num, y: prev[prev.length - 1].y - length2Num }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Ref.current === '←' && arrow2Ref.current === '↓') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x - length1Num, y: prev[prev.length - 1].y + length2Num }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Ref.current === '←' && arrow2Ref.current === '↑') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x - length1Num, y: prev[prev.length - 1].y - length2Num }]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//이구배 완료될 경우 확인 ↓, ↑, ←, →
|
||||||
|
const checkDoublePitch = (direction) => {
|
||||||
|
const activeElem = document.activeElement
|
||||||
|
|
||||||
|
const canDirection =
|
||||||
|
direction === '↓' || direction === '↑'
|
||||||
|
? arrow1Ref.current === '←' || arrow1Ref.current === '→'
|
||||||
|
: arrow1Ref.current === '↓' || arrow1Ref.current === '↑'
|
||||||
|
|
||||||
|
if (activeElem === length1Ref.current || activeElem === angle1Ref.current) {
|
||||||
|
setArrow1(direction)
|
||||||
|
arrow1Ref.current = direction
|
||||||
|
angle2Ref.current.focus()
|
||||||
|
} else if (activeElem === length2Ref.current || activeElem === angle2Ref.current) {
|
||||||
|
if (!canDirection) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setArrow2(direction)
|
||||||
|
arrow2Ref.current = direction
|
||||||
|
}
|
||||||
|
|
||||||
|
const angle1Value = angle1Ref.current.value
|
||||||
|
const angle2Value = angle2Ref.current.value
|
||||||
|
const length1Value = length1Ref.current.value
|
||||||
|
const length2Value = length2Ref.current.value
|
||||||
|
|
||||||
|
const arrow1Value = arrow1Ref.current
|
||||||
|
const arrow2Value = arrow2Ref.current
|
||||||
|
|
||||||
|
if (angle1Value !== 0 && length1Value !== 0 && angle2Value !== 0 && arrow1Value !== '' && arrow2Value !== '') {
|
||||||
|
if (arrow1Value === '↓' && arrow2Value === '→') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x + length1Value / 10, y: prev[prev.length - 1].y + length2Value / 10 }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Value === '↓' && arrow2Value === '←') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x - length1Value / 10, y: prev[prev.length - 1].y + length2Value / 10 }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Value === '↑' && arrow2Value === '→') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x + length1Value / 10, y: prev[prev.length - 1].y - length2Value / 10 }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Value === '↑' && arrow2Value === '←') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x - length1Value / 10, y: prev[prev.length - 1].y - length2Value / 10 }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Value === '→' && arrow2Value === '↓') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Value === '→' && arrow2Value === '↑') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Value === '←' && arrow2Value === '↓') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Value === '←' && arrow2Value === '↑') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
angle1Ref.current.focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//대각선 완료될 경우 확인
|
||||||
|
const checkDiagonal = (direction) => {
|
||||||
|
const activeElem = document.activeElement
|
||||||
|
const diagonalLength = outerLineDiagonalLengthRef.current.value // 대각선 길이
|
||||||
|
|
||||||
|
const length1Value = length1Ref.current.value
|
||||||
|
|
||||||
|
if (diagonalLength <= length1Value) {
|
||||||
|
alert('대각선 길이는 직선 길이보다 길어야 합니다.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const canDirection =
|
||||||
|
direction === '↓' || direction === '↑'
|
||||||
|
? arrow1Ref.current === '←' || arrow1Ref.current === '→'
|
||||||
|
: arrow1Ref.current === '↓' || arrow1Ref.current === '↑'
|
||||||
|
|
||||||
|
if (activeElem === length1Ref.current) {
|
||||||
|
setArrow1(direction)
|
||||||
|
arrow1Ref.current = direction
|
||||||
|
} else if (activeElem === length2Ref.current || activeElem === angle2Ref.current) {
|
||||||
|
if (!canDirection) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setArrow2(direction)
|
||||||
|
arrow2Ref.current = direction
|
||||||
|
}
|
||||||
|
|
||||||
|
const arrow1Value = arrow1Ref.current
|
||||||
|
const arrow2Value = arrow2Ref.current
|
||||||
|
|
||||||
|
const getLength2 = () => {
|
||||||
|
return Math.floor(Math.sqrt(diagonalLength ** 2 - length1Value ** 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
const length2Value = getLength2()
|
||||||
|
|
||||||
|
if (diagonalLength !== 0 && length1Value !== 0 && arrow1Value !== '') {
|
||||||
|
setLength2(getLength2())
|
||||||
|
length2Ref.current.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length1Value !== 0 && length2Value !== 0 && arrow1Value !== '' && arrow2Value !== '') {
|
||||||
|
if (arrow1Value === '↓' && arrow2Value === '→') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Value === '↓' && arrow2Value === '←') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Value === '↑' && arrow2Value === '→') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Value === '↑' && arrow2Value === '←') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Value === '→' && arrow2Value === '↓') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x + length1Value / 10, y: prev[prev.length - 1].y + length2Value / 10 }]
|
||||||
|
})
|
||||||
|
} else if (arrow1Value === '→' && arrow2Value === '↑') {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
...prev,
|
||||||
|
{
|
||||||
|
x: prev[prev.length - 1].x + length1Value / 10,
|
||||||
|
y: prev[prev.length - 1].y - length2Value / 10,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const keydown = {
|
||||||
|
outerLine: (e) => {
|
||||||
|
if (points.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 포커스가 length1에 있지 않으면 length1에 포커스를 줌
|
||||||
|
const activeElem = document.activeElement
|
||||||
|
if (activeElem !== length1Ref.current) {
|
||||||
|
length1Ref.current.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = e.key
|
||||||
|
|
||||||
|
if (!length1Ref.current) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const lengthNum = Number(length1Ref.current.value) / 10
|
||||||
|
if (lengthNum === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch (key) {
|
||||||
|
case 'Down': // IE/Edge에서 사용되는 값
|
||||||
|
case 'ArrowDown': {
|
||||||
|
setArrow1('↓')
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x, y: prev[prev.length - 1].y + lengthNum }]
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'Up': // IE/Edge에서 사용되는 값
|
||||||
|
case 'ArrowUp':
|
||||||
|
setArrow1('↑')
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x, y: prev[prev.length - 1].y - lengthNum }]
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'Left': // IE/Edge에서 사용되는 값
|
||||||
|
case 'ArrowLeft':
|
||||||
|
setArrow1('←')
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x - lengthNum, y: prev[prev.length - 1].y }]
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'Right': // IE/Edge에서 사용되는 값
|
||||||
|
case 'ArrowRight':
|
||||||
|
setArrow1('→')
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [...prev, { x: prev[prev.length - 1].x + lengthNum, y: prev[prev.length - 1].y }]
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rightAngle: (e) => {
|
||||||
|
if (points.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const key = e.key
|
||||||
|
|
||||||
|
const activeElem = document.activeElement
|
||||||
|
if (activeElem !== length1Ref.current && activeElem !== length2Ref.current) {
|
||||||
|
length1Ref.current.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case 'Down': // IE/Edge에서 사용되는 값
|
||||||
|
case 'ArrowDown': {
|
||||||
|
checkRightAngle('↓')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'Up': // IE/Edge에서 사용되는 값
|
||||||
|
case 'ArrowUp':
|
||||||
|
checkRightAngle('↑')
|
||||||
|
break
|
||||||
|
case 'Left': // IE/Edge에서 사용되는 값
|
||||||
|
case 'ArrowLeft':
|
||||||
|
checkRightAngle('←')
|
||||||
|
break
|
||||||
|
case 'Right': // IE/Edge에서 사용되는 값
|
||||||
|
case 'ArrowRight':
|
||||||
|
checkRightAngle('→')
|
||||||
|
break
|
||||||
|
case 'Enter':
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
doublePitch: (e) => {
|
||||||
|
if (points.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const key = e.key
|
||||||
|
switch (key) {
|
||||||
|
case 'Down': // IE/Edge에서 사용되는 값
|
||||||
|
case 'ArrowDown': {
|
||||||
|
checkDoublePitch('↓')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'Up': // IE/Edge에서 사용되는 값
|
||||||
|
case 'ArrowUp':
|
||||||
|
checkDoublePitch('↑')
|
||||||
|
break
|
||||||
|
case 'Left': // IE/Edge에서 사용되는 값
|
||||||
|
case 'ArrowLeft':
|
||||||
|
checkDoublePitch('←')
|
||||||
|
break
|
||||||
|
case 'Right': // IE/Edge에서 사용되는 값
|
||||||
|
case 'ArrowRight':
|
||||||
|
checkDoublePitch('→')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
angle: (e) => {
|
||||||
|
if (points.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const key = e.key
|
||||||
|
switch (key) {
|
||||||
|
case 'Enter': {
|
||||||
|
setPoints((prev) => {
|
||||||
|
if (prev.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const lastPoint = prev[prev.length - 1]
|
||||||
|
const length = length1Ref.current.value / 10
|
||||||
|
const angle = angle1Ref.current.value
|
||||||
|
//lastPoint로부터 angle1만큼의 각도로 length1만큼의 길이를 가지는 선을 그림
|
||||||
|
const radian = (angle * Math.PI) / 180
|
||||||
|
|
||||||
|
const x = lastPoint.x + length * Math.cos(radian)
|
||||||
|
const y = lastPoint.y - length * Math.sin(radian)
|
||||||
|
return [...prev, { x, y }]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
diagonalLine: (e) => {
|
||||||
|
if (points.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = e.key
|
||||||
|
switch (key) {
|
||||||
|
case 'Down': // IE/Edge에서 사용되는 값
|
||||||
|
case 'ArrowDown': {
|
||||||
|
checkDiagonal('↓')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'Up': // IE/Edge에서 사용되는 값
|
||||||
|
case 'ArrowUp':
|
||||||
|
checkDiagonal('↑')
|
||||||
|
break
|
||||||
|
case 'Left': // IE/Edge에서 사용되는 값
|
||||||
|
case 'ArrowLeft':
|
||||||
|
checkDiagonal('←')
|
||||||
|
break
|
||||||
|
case 'Right': // IE/Edge에서 사용되는 값
|
||||||
|
case 'ArrowRight':
|
||||||
|
checkDiagonal('→')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 일변전으로 돌아가기
|
||||||
|
*/
|
||||||
|
const handleRollback = () => {
|
||||||
|
//points의 마지막 요소를 제거
|
||||||
|
setPoints((prev) => prev.slice(0, prev.length - 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleFix = () => {
|
||||||
|
if (points.length < 3) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let isAllRightAngle = true
|
||||||
|
|
||||||
|
const firstPoint = points[0]
|
||||||
|
|
||||||
|
points.forEach((point, idx) => {
|
||||||
|
if (idx === 0 || !isAllRightAngle) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const angle = calculateAngle(point, firstPoint)
|
||||||
|
if (angle % 90 !== 0) {
|
||||||
|
isAllRightAngle = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (isAllRightAngle) {
|
||||||
|
alert('부정확한 다각형입니다.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setPoints((prev) => {
|
||||||
|
return [...prev, { x: prev[0].x, y: prev[0].y }]
|
||||||
|
})
|
||||||
|
|
||||||
|
isFix.current = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
points,
|
||||||
|
setPoints,
|
||||||
|
length1,
|
||||||
|
setLength1,
|
||||||
|
length2,
|
||||||
|
setLength2,
|
||||||
|
length1Ref,
|
||||||
|
length2Ref,
|
||||||
|
arrow1,
|
||||||
|
setArrow1,
|
||||||
|
arrow2,
|
||||||
|
setArrow2,
|
||||||
|
arrow1Ref,
|
||||||
|
arrow2Ref,
|
||||||
|
angle1,
|
||||||
|
setAngle1,
|
||||||
|
angle1Ref,
|
||||||
|
angle2,
|
||||||
|
setAngle2,
|
||||||
|
angle2Ref,
|
||||||
|
outerLineDiagonalLength,
|
||||||
|
setOuterLineDiagonalLength,
|
||||||
|
outerLineDiagonalLengthRef,
|
||||||
|
type,
|
||||||
|
setType,
|
||||||
|
handleFix,
|
||||||
|
handleRollback,
|
||||||
|
}
|
||||||
|
}
|
||||||
70
src/store/placementShapeDrawingAtom.js
Normal file
70
src/store/placementShapeDrawingAtom.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import { atom } from 'recoil'
|
||||||
|
|
||||||
|
export const OUTER_LINE_TYPE = {
|
||||||
|
OUTER_LINE: 'outerLine', // 외벽선
|
||||||
|
RIGHT_ANGLE: 'rightAngle', // 직각
|
||||||
|
DOUBLE_PITCH: 'doublePitch',
|
||||||
|
ANGLE: 'angle', // 각도
|
||||||
|
DIAGONAL_LINE: 'diagonalLine', // 대각선
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 외벽선 작성에서 사용하는 recoilState
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const placementShapeDrawingLength1State = atom({
|
||||||
|
//길이1
|
||||||
|
key: 'placementShapeDrawingLength1State',
|
||||||
|
default: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const placementShapeDrawingLength2State = atom({
|
||||||
|
// 길이2
|
||||||
|
key: 'placementShapeDrawingLength2State',
|
||||||
|
default: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const placementShapeDrawingArrow1State = atom({
|
||||||
|
// 방향1
|
||||||
|
key: 'placementShapeDrawingArrow1State',
|
||||||
|
default: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const placementShapeDrawingArrow2State = atom({
|
||||||
|
// 방향2
|
||||||
|
key: 'placementShapeDrawingArrow2State',
|
||||||
|
default: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const placementShapeDrawingAngle1State = atom({
|
||||||
|
// 각도1
|
||||||
|
key: 'placementShapeDrawingAngle1State',
|
||||||
|
default: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const placementShapeDrawingAngle2State = atom({
|
||||||
|
// 각도2
|
||||||
|
key: 'placementShapeDrawingAngle2State',
|
||||||
|
default: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const placementShapeDrawingDiagonalState = atom({
|
||||||
|
// 대각선
|
||||||
|
key: 'placementShapeDrawingDiagonalState',
|
||||||
|
default: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const placementShapeDrawingTypeState = atom({
|
||||||
|
key: 'placementShapeDrawingTypeState',
|
||||||
|
default: OUTER_LINE_TYPE.OUTER_LINE,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const placementShapeDrawingPointsState = atom({
|
||||||
|
key: 'placementShapeDrawingPointsState',
|
||||||
|
default: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const placementShapeDrawingFixState = atom({
|
||||||
|
key: 'placementShapeDrawingFixState',
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
Loading…
x
Reference in New Issue
Block a user