보조선 작성 추가

This commit is contained in:
hyojun.choi 2024-10-08 10:35:22 +09:00
parent d4e2952024
commit 0825196cea
6 changed files with 697 additions and 49 deletions

View File

@ -17,7 +17,7 @@ import GridColorSetting from './modal/grid/GridColorSetting'
import RoofShapeSetting from '@/components/floor-plan/modal/roofShape/RoofShapeSetting' import RoofShapeSetting from '@/components/floor-plan/modal/roofShape/RoofShapeSetting'
import PlacementShapeDrawing from '@/components/floor-plan/modal/placementShape/PlacementShapeDrawing' import PlacementShapeDrawing from '@/components/floor-plan/modal/placementShape/PlacementShapeDrawing'
import Slope from '@/components/floor-plan/modal/Slope' import Slope from '@/components/floor-plan/modal/Slope'
import RoofShapePassivitySetting from '@/components/floor-plan/modal/roofShape/RoofShapePassivitySetting'
import AuxiliaryDrawing from '@/components/floor-plan/modal/auxiliary/AuxiliaryDrawing' import AuxiliaryDrawing from '@/components/floor-plan/modal/auxiliary/AuxiliaryDrawing'
export default function FloorPlan() { export default function FloorPlan() {
@ -122,9 +122,6 @@ export default function FloorPlan() {
{showPropertiesSettingModal && <PropertiesSetting {...propertiesSettingProps} />} {showPropertiesSettingModal && <PropertiesSetting {...propertiesSettingProps} />}
{showPlaceShapeModal && <PlacementShapeSetting setShowPlaceShapeModal={setShowPlaceShapeModal} />} {showPlaceShapeModal && <PlacementShapeSetting setShowPlaceShapeModal={setShowPlaceShapeModal} />}
{showRoofShapeSettingModal && <RoofShapeSetting setShowRoofShapeSettingModal={setShowRoofShapeSettingModal} />} {showRoofShapeSettingModal && <RoofShapeSetting setShowRoofShapeSettingModal={setShowRoofShapeSettingModal} />}
{showRoofShapePassivitySettingModal && (
<RoofShapePassivitySetting setShowRoofShapePassivitySettingModal={setShowRoofShapePassivitySettingModal} />
)}
{showAuxiliaryModal && <AuxiliaryDrawing setShowAuxiliaryModal={setShowAuxiliaryModal} />} {showAuxiliaryModal && <AuxiliaryDrawing setShowAuxiliaryModal={setShowAuxiliaryModal} />}
{showSlopeSettingModal && <Slope setShowSlopeSettingModal={setShowSlopeSettingModal} />} {showSlopeSettingModal && <Slope setShowSlopeSettingModal={setShowSlopeSettingModal} />}
{showPlaceShapeDrawingModal && <PlacementShapeDrawing setShowPlaceShapeDrawingModal={setShowPlaceShapeDrawingModal} />} {showPlaceShapeDrawingModal && <PlacementShapeDrawing setShowPlaceShapeDrawingModal={setShowPlaceShapeDrawingModal} />}

View File

@ -8,10 +8,11 @@ import Diagonal from '@/components/floor-plan/modal/lineTypes/Diagonal'
import { OUTER_LINE_TYPE } from '@/store/outerLineAtom' import { OUTER_LINE_TYPE } from '@/store/outerLineAtom'
import { useOuterLineWall } from '@/hooks/roofcover/useOuterLineWall' import { useOuterLineWall } from '@/hooks/roofcover/useOuterLineWall'
import OuterLineWall from '@/components/floor-plan/modal/lineTypes/OuterLineWall' import OuterLineWall from '@/components/floor-plan/modal/lineTypes/OuterLineWall'
import { useAuxiliaryDrawing } from '@/hooks/roofcover/useAuxiliaryDrawing'
export default function AuxiliaryDrawing({ setShowAuxiliaryModal }) { export default function AuxiliaryDrawing({ setShowAuxiliaryModal }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const [buttonAct, setButtonAct] = useState(1)
const types = [ const types = [
{ id: 1, name: getMessage('straight.line'), type: OUTER_LINE_TYPE.OUTER_LINE }, { id: 1, name: getMessage('straight.line'), type: OUTER_LINE_TYPE.OUTER_LINE },
{ id: 2, name: getMessage('right.angle'), type: OUTER_LINE_TYPE.RIGHT_ANGLE }, { id: 2, name: getMessage('right.angle'), type: OUTER_LINE_TYPE.RIGHT_ANGLE },
@ -19,6 +20,7 @@ export default function AuxiliaryDrawing({ setShowAuxiliaryModal }) {
{ id: 4, name: getMessage('angle'), type: OUTER_LINE_TYPE.ANGLE }, { id: 4, name: getMessage('angle'), type: OUTER_LINE_TYPE.ANGLE },
{ id: 5, name: getMessage('diagonal'), type: OUTER_LINE_TYPE.DIAGONAL_LINE }, { id: 5, name: getMessage('diagonal'), type: OUTER_LINE_TYPE.DIAGONAL_LINE },
] ]
const { const {
length1, length1,
setLength1, setLength1,
@ -45,7 +47,9 @@ export default function AuxiliaryDrawing({ setShowAuxiliaryModal }) {
outerLineDiagonalLengthRef, outerLineDiagonalLengthRef,
handleRollback, handleRollback,
handleFix, handleFix,
} = useOuterLineWall() buttonAct,
setButtonAct,
} = useAuxiliaryDrawing()
const outerLineProps = { const outerLineProps = {
length1, length1,
@ -129,8 +133,8 @@ export default function AuxiliaryDrawing({ setShowAuxiliaryModal }) {
</div> </div>
<div className="modal-body"> <div className="modal-body">
<div className="modal-btn-wrap"> <div className="modal-btn-wrap">
{types.map((type) => ( {types.map((type, idx) => (
<button className={`btn-frame modal ${buttonAct === type.id ? 'act' : ''}`} onClick={() => onClickButton(type)}> <button key={idx} className={`btn-frame modal ${buttonAct === type.id ? 'act' : ''}`} onClick={() => onClickButton(type)}>
{type.name} {type.name}
</button> </button>
))} ))}
@ -144,8 +148,12 @@ export default function AuxiliaryDrawing({ setShowAuxiliaryModal }) {
{buttonAct === 5 && <Diagonal props={diagonalLineProps} />} {buttonAct === 5 && <Diagonal props={diagonalLineProps} />}
</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(setShowAuxiliaryModal)}>
{getMessage('modal.cover.outline.fix')}
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,663 @@
import { useEffect, useRef, useState } from 'react'
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 {
OUTER_LINE_TYPE,
outerLineAngle1State,
outerLineAngle2State,
outerLineArrow1State,
outerLineArrow2State,
outerLineDiagonalState,
outerLineLength1State,
outerLineLength2State,
outerLineTypeState,
} from '@/store/outerLineAtom'
import { calculateDistance, calculateIntersection, distanceBetweenPoints, findClosestPoint } from '@/util/canvas-util'
import { fabric } from 'fabric'
import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint'
export function useAuxiliaryDrawing() {
const canvas = useRecoilValue(canvasState)
const {
addCanvasMouseEventListener,
addDocumentEventListener,
removeAllMouseEventListeners,
removeAllDocumentEventListeners,
removeMouseEvent,
removeMouseLine,
initEvent,
} = useEvent()
const { getIntersectMousePoint } = useMouse()
const { addLine, removeLine } = useLine()
const { tempGridMode } = useTempGrid()
const { getAdsorptionPoints } = useAdsorptionPoint()
const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState)
const adsorptionPointAddMode = useRecoilValue(adsorptionPointAddModeState)
const adsorptionPointMode = useRecoilValue(adsorptionPointModeState)
const adsorptionRange = useRecoilValue(adsorptionRangeState)
const interval = useRecoilValue(dotLineIntervalSelector) // 가로 세로 간격
const [buttonAct, setButtonAct] = useState(1)
const mousePointerArr = useRef([])
const roofAdsorptionPoints = useRef([])
const lineHistory = useRef([])
const length1Ref = useRef(0)
const length2Ref = useRef(0)
const angle1Ref = useRef('')
const angle2Ref = useRef('')
const [length1, setLength1] = useRecoilState(outerLineLength1State)
const [length2, setLength2] = useRecoilState(outerLineLength2State)
const [arrow1, setArrow1] = useRecoilState(outerLineArrow1State)
const [arrow2, setArrow2] = useRecoilState(outerLineArrow2State)
const [type, setType] = useRecoilState(outerLineTypeState)
const [angle1, setAngle1] = useRecoilState(outerLineAngle1State)
const [angle2, setAngle2] = useRecoilState(outerLineAngle2State)
const [outerLineDiagonalLength, setOuterLineDiagonalLength] = useRecoilState(outerLineDiagonalState)
const arrow1Ref = useRef(arrow1)
const arrow2Ref = useRef(arrow2)
const typeRef = useRef(type)
const outerLineDiagonalLengthRef = useRef(0)
const intersectionPoints = useRef([])
useEffect(() => {
arrow1Ref.current = arrow1
}, [arrow1])
useEffect(() => {
arrow2Ref.current = arrow2
}, [arrow2])
useEffect(() => {
typeRef.current = type
}, [type])
useEffect(() => {
// innerLines가 있을경우 삭제
const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roofBase')
if (roofs.length === 0) {
return
}
// 지붕의 각 꼭지점을 흡착점으로 설정
const roofsPoints = roofs.map((roof) => roof.points).flat()
roofAdsorptionPoints.current = [...roofsPoints]
addCanvasMouseEventListener('mouse:move', mouseMove)
addCanvasMouseEventListener('mouse:down', mouseDown)
addDocumentEventListener('contextmenu', document, cutAuxiliary)
addDocumentEventListener('keydown', document, keydown)
return () => {
canvas.remove(...canvas.getObjects().filter((obj) => obj.name === 'innerPoint'))
initEvent()
canvas.renderAll()
}
}, [])
useEffect(() => {
clear()
addDocumentEventListener('keydown', document, keydown[type])
}, [type])
const clear = () => {
setLength1(0)
setLength2(0)
setArrow1('')
setArrow2('')
setAngle1(0)
setAngle2(0)
setOuterLineDiagonalLength(0)
}
const keydown = {
outerLine: (e) => {
console.log(123)
if (mousePointerArr.current.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
}
const lastPoint = mousePointerArr.current[0]
switch (key) {
case 'Down': // IE/Edge에서 사용되는 값
case 'ArrowDown': {
setArrow1('↓')
mousePointerArr.current.push({ x: lastPoint.x, y: lastPoint.y + lengthNum })
drawLine()
break
}
case 'Up': // IE/Edge에서 사용되는 값
case 'ArrowUp':
setArrow1('↑')
mousePointerArr.current.push({ x: lastPoint.x, y: lastPoint.y - lengthNum })
drawLine()
break
case 'Left': // IE/Edge에서 사용되는 값
case 'ArrowLeft':
setArrow1('←')
mousePointerArr.current.push({ x: lastPoint.x - lengthNum, y: lastPoint.y })
drawLine()
break
case 'Right': // IE/Edge에서 사용되는 값
case 'ArrowRight':
setArrow1('→')
mousePointerArr.current.push({ x: lastPoint.x + lengthNum, y: lastPoint.y })
drawLine()
break
}
},
rightAngle: (e) => {
if (mousePointerArr.current.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
}
},
doublePitch: (e) => {
if (mousePointerArr.current.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 (mousePointerArr.current.length === 0) {
return
}
const key = e.key
switch (key) {
case 'Enter': {
const lastPoint = mousePointerArr.current[0]
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 (mousePointerArr.current.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 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 (mousePointerArr.current.length === 0) {
return
}
const lastPoint = mousePointerArr.current[0]
if (length1Num === 0 || length2Num === 0 || arrow1Ref.current === '' || arrow2Ref.current === '') {
return
}
if (arrow1Ref.current === '↓' && arrow2Ref.current === '→') {
mousePointerArr.current.push({ x: lastPoint.x + length2Num, y: lastPoint.y + length1Num })
} else if (arrow1Ref.current === '↓' && arrow2Ref.current === '←') {
mousePointerArr.current.push({ x: lastPoint.x - length2Num, y: lastPoint.y + length1Num })
} else if (arrow1Ref.current === '↑' && arrow2Ref.current === '→') {
mousePointerArr.current.push({ x: lastPoint.x + length2Num, y: lastPoint.y - length1Num })
} else if (arrow1Ref.current === '↑' && arrow2Ref.current === '←') {
mousePointerArr.current.push({ x: lastPoint.x - length2Num, y: lastPoint.y - length1Num })
} else if (arrow1Ref.current === '→' && arrow2Ref.current === '↓') {
mousePointerArr.current.push({ x: lastPoint.x + length1Num, y: lastPoint.y + length2Num })
} else if (arrow1Ref.current === '→' && arrow2Ref.current === '↑') {
mousePointerArr.current.push({ x: lastPoint.x + length1Num, y: lastPoint.y - length2Num })
} else if (arrow1Ref.current === '←' && arrow2Ref.current === '↓') {
mousePointerArr.current.push({ x: lastPoint.x - length1Num, y: lastPoint.y + length2Num })
} else if (arrow1Ref.current === '←' && arrow2Ref.current === '↑') {
mousePointerArr.current.push({ x: lastPoint.x - length1Num, y: lastPoint.y - length2Num })
}
drawLine()
}
//이구배 완료될 경우 확인 ↓, ↑, ←, →
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 = Number(angle1Ref.current.value)
const angle2Value = Number(angle2Ref.current.value)
const length1Value = Number(length1Ref.current.value)
const length2Value = Number(length2Ref.current.value)
const arrow1Value = arrow1Ref.current
const arrow2Value = arrow2Ref.current
const lastPoint = mousePointerArr.current[0]
if (angle1Value !== 0 && length1Value !== 0 && angle2Value !== 0 && arrow1Value !== '' && arrow2Value !== '') {
if (arrow1Value === '↓' && arrow2Value === '→') {
mousePointerArr.current.push({ x: lastPoint.x + length1Value / 10, y: lastPoint.y + length2Value / 10 })
} else if (arrow1Value === '↓' && arrow2Value === '←') {
mousePointerArr.current.push({ x: lastPoint.x - length1Value / 10, y: lastPoint.y + length2Value / 10 })
} else if (arrow1Value === '↑' && arrow2Value === '→') {
mousePointerArr.current.push({ x: lastPoint.x + length1Value / 10, y: lastPoint.y - length2Value / 10 })
} else if (arrow1Value === '↑' && arrow2Value === '←') {
mousePointerArr.current.push({ x: lastPoint.x - length1Value / 10, y: lastPoint.y - length2Value / 10 })
} else if (arrow1Value === '→' && arrow2Value === '↓') {
mousePointerArr.current.push({ x: lastPoint.x + length2Value / 10, y: lastPoint.y + length1Value / 10 })
} else if (arrow1Value === '→' && arrow2Value === '↑') {
mousePointerArr.current.push({ x: lastPoint.x + length2Value / 10, y: lastPoint.y - length1Value / 10 })
} else if (arrow1Value === '←' && arrow2Value === '↓') {
mousePointerArr.current.push({ x: lastPoint.x - length2Value / 10, y: lastPoint.y + length1Value / 10 })
} else if (arrow1Value === '←' && arrow2Value === '↑') {
mousePointerArr.current.push({ x: lastPoint.x - length2Value / 10, y: lastPoint.y - length1Value / 10 })
}
drawLine()
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()
}
const lastPoint = mousePointerArr.current[0]
if (length1Value !== 0 && length2Value !== 0 && arrow1Value !== '' && arrow2Value !== '') {
if (arrow1Value === '↓' && arrow2Value === '→') {
mousePointerArr.current.push({ x: lastPoint.x + length2Value / 10, y: lastPoint.y + length1Value / 10 })
} else if (arrow1Value === '↓' && arrow2Value === '←') {
mousePointerArr.current.push({ x: lastPoint.x - length2Value / 10, y: lastPoint.y + length1Value / 10 })
} else if (arrow1Value === '↑' && arrow2Value === '→') {
mousePointerArr.current.push({ x: lastPoint.x + length2Value / 10, y: lastPoint.y - length1Value / 10 })
} else if (arrow1Value === '↑' && arrow2Value === '←') {
mousePointerArr.current.push({ x: lastPoint.x - length2Value / 10, y: lastPoint.y - length1Value / 10 })
} else if (arrow1Value === '→' && arrow2Value === '↓') {
mousePointerArr.current.push({ x: lastPoint.x + length1Value / 10, y: lastPoint.y + length2Value / 10 })
} else if (arrow1Value === '→' && arrow2Value === '↑') {
mousePointerArr.current.push({ x: lastPoint.x + length1Value / 10, y: lastPoint.y - length2Value / 10 })
}
drawLine()
}
}
const drawLine = () => {
canvas.remove(...canvas.getObjects().filter((obj) => obj.name === 'innerPoint'))
const line = addLine([mousePointerArr.current[0].x, mousePointerArr.current[0].y, mousePointerArr.current[1].x, mousePointerArr.current[1].y], {
stroke: 'black',
strokeWidth: 1,
selectable: false,
name: 'auxiliaryLine',
})
lineHistory.current.push(line)
mousePointerArr.current = []
clear()
}
const mouseDown = (e) => {
const pointer = getIntersectMousePoint(e)
mousePointerArr.current.push(pointer)
if (mousePointerArr.current.length === 2) {
drawLine(mousePointerArr.current[0], mousePointerArr.current[1])
} else {
const circle = new fabric.Circle({
radius: 3,
fill: 'red',
left: pointer.x - 3,
top: pointer.y - 3,
x: pointer.x,
y: pointer.y,
name: 'innerPoint',
selectable: true,
})
canvas.add(circle)
canvas.renderAll()
}
}
const mouseMove = (e) => {
removeMouseLine()
// 가로선
const pointer = canvas.getPointer(e.e)
const auxiliaryLines = canvas.getObjects().filter((obj) => obj.name === 'auxiliaryLine' && !obj.isFixed)
const otherAdsorptionPoints = []
auxiliaryLines.forEach((line1) => {
auxiliaryLines.forEach((line2) => {
const lines = [line1, line2]
if (line1 === line2) {
return
}
const intersectionPoint = calculateIntersection(line1, line2)
if (!intersectionPoint || intersectionPoints.current.some((point) => point.x === intersectionPoint.x && point.y === intersectionPoint.y)) {
return
}
otherAdsorptionPoints.push(intersectionPoint)
})
})
const adsorptionPoints = [...getAdsorptionPoints(), ...roofAdsorptionPoints.current, ...otherAdsorptionPoints, ...intersectionPoints.current]
let arrivalPoint = { x: pointer.x, y: pointer.y }
// pointer와 adsorptionPoints의 거리를 계산하여 가장 가까운 점을 찾는다.
let adsorptionPoint = findClosestPoint(pointer, adsorptionPoints)
if (adsorptionPoint && distanceBetweenPoints(pointer, adsorptionPoint) <= adsorptionRange) {
arrivalPoint = { ...adsorptionPoint }
}
const horizontalLine = new fabric.Line([-1 * canvas.width, arrivalPoint.y, 2 * canvas.width, arrivalPoint.y], {
stroke: 'red',
strokeWidth: 1,
selectable: false,
name: 'mouseLine',
})
// 세로선
const verticalLine = new fabric.Line([arrivalPoint.x, -1 * canvas.height, arrivalPoint.x, 2 * canvas.height], {
stroke: 'red',
strokeWidth: 1,
selectable: false,
name: 'mouseLine',
})
// 선들을 캔버스에 추가합니다.
canvas?.add(horizontalLine, verticalLine)
// 캔버스를 다시 그립니다.
canvas?.renderAll()
}
// 보조선 절삭
const cutAuxiliary = (e) => {
const auxiliaryLines = canvas.getObjects().filter((obj) => obj.name === 'auxiliaryLine' && !obj.isFixed)
if (auxiliaryLines.length === 0) {
return
}
auxiliaryLines.forEach((line1) => {
auxiliaryLines.forEach((line2) => {
const lines = [line1, line2]
if (line1 === line2) {
return
}
const intersectionPoint = calculateIntersection(line1, line2)
if (!intersectionPoint || intersectionPoints.current.some((point) => point.x === intersectionPoint.x && point.y === intersectionPoint.y)) {
return
}
roofAdsorptionPoints.current.push(intersectionPoint)
intersectionPoints.current.push(intersectionPoint)
lines.forEach((line) => {
const distance1 = distanceBetweenPoints({ x: line.x1, y: line.y1 }, intersectionPoint)
const distance2 = distanceBetweenPoints({ x: line.x2, y: line.y2 }, intersectionPoint)
if (distance1 === 0 || distance2 === 0) {
return
}
//historyLine에서 기존 line을 제거한다.
lineHistory.current = lineHistory.current.filter((history) => history !== line)
let newLine
if (distance1 >= distance2) {
newLine = addLine([line.x1, line.y1, intersectionPoint.x, intersectionPoint.y], {
stroke: 'black',
strokeWidth: 1,
selectable: false,
name: 'auxiliaryLine',
isFixed: true,
intersectionPoint,
})
} else {
newLine = addLine([line.x2, line.y2, intersectionPoint.x, intersectionPoint.y], {
stroke: 'black',
strokeWidth: 1,
selectable: false,
name: 'auxiliaryLine',
isFixed: true,
intersectionPoint,
})
}
lineHistory.current.push(newLine)
removeLine(line)
})
})
})
addCanvasMouseEventListener('mouse:move', mouseMove)
}
/**
* 일변전으로 돌아가기
*/
const handleRollback = () => {
const lastLine = lineHistory.current.pop()
mousePointerArr.current = []
canvas.remove(...canvas.getObjects().filter((obj) => obj.name === 'innerPoint'))
if (lastLine) {
roofAdsorptionPoints.current = roofAdsorptionPoints.current.filter(
(point) => point.x !== lastLine.intersectionPoint?.x && point.y !== lastLine.intersectionPoint?.y,
)
canvas.remove(lastLine)
canvas.renderAll()
}
addCanvasMouseEventListener('mouse:move', mouseMove)
}
const handleFix = (fn) => {
if (!confirm('지붕선 완료하시겠습니까?')) {
return
}
fn(close)
}
return {
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,
buttonAct,
setButtonAct,
}
}

View File

@ -44,7 +44,7 @@ export function useOuterLineWall() {
const adsorptionPointMode = useRecoilValue(adsorptionPointModeState) const adsorptionPointMode = useRecoilValue(adsorptionPointModeState)
const adsorptionRange = useRecoilValue(adsorptionRangeState) const adsorptionRange = useRecoilValue(adsorptionRangeState)
const interval = useRecoilValue(dotLineIntervalSelector) // 가로 세로 간격 const interval = useRecoilValue(dotLineIntervalSelector) // 가로 세로 간격
const currentCanvasPlan = useRecoilValue(currentCanvasPlanState)
const length1Ref = useRef(null) const length1Ref = useRef(null)
const length2Ref = useRef(null) const length2Ref = useRef(null)
const angle1Ref = useRef(null) const angle1Ref = useRef(null)
@ -91,23 +91,6 @@ export function useOuterLineWall() {
addDocumentEventListener('keydown', document, keydown[type]) addDocumentEventListener('keydown', document, keydown[type])
}, [type]) }, [type])
useEffect(() => {
canvas
?.getObjects()
.filter((obj) => obj.name !== 'outerLinePoint')
.forEach((obj) => canvas.remove(obj))
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 = () => { const clear = () => {
setLength1(0) setLength1(0)
setLength2(0) setLength2(0)
@ -490,6 +473,14 @@ export function useOuterLineWall() {
//대각선 완료될 경우 확인 //대각선 완료될 경우 확인
const checkDiagonal = (direction) => { const checkDiagonal = (direction) => {
const activeElem = document.activeElement const activeElem = document.activeElement
const diagonalLength = outerLineDiagonalLengthRef.current.value // 대각선 길이
const length1Value = length1Ref.current.value
if (diagonalLength <= length1Value) {
alert('대각선 길이는 직선 길이보다 길어야 합니다.')
return
}
const canDirection = const canDirection =
direction === '↓' || direction === '↑' direction === '↓' || direction === '↑'
@ -507,10 +498,6 @@ export function useOuterLineWall() {
arrow2Ref.current = direction arrow2Ref.current = direction
} }
const diagonalLength = outerLineDiagonalLengthRef.current.value // 대각선 길이
const length1Value = length1Ref.current.value
const arrow1Value = arrow1Ref.current const arrow1Value = arrow1Ref.current
const arrow2Value = arrow2Ref.current const arrow2Value = arrow2Ref.current
@ -672,6 +659,8 @@ export function useOuterLineWall() {
case 'ArrowRight': case 'ArrowRight':
checkRightAngle('→') checkRightAngle('→')
break break
case 'Enter':
break
} }
}, },
doublePitch: (e) => { doublePitch: (e) => {

View File

@ -30,17 +30,6 @@ export function useRoofShapeSetting() {
const history = useRef([]) 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(() => { useEffect(() => {
if (shapeNum !== 4) { if (shapeNum !== 4) {
return return
@ -118,9 +107,6 @@ export function useRoofShapeSetting() {
let outerLines let outerLines
canvas?.remove(canvas.getObjects().find((obj) => obj.name === 'wallLine'))
canvas?.remove(canvas.getObjects().find((obj) => obj.name === 'roofBase'))
switch (shapeNum) { switch (shapeNum) {
case 1: { case 1: {
outerLines = saveRidge() outerLines = saveRidge()

View File

@ -21,6 +21,10 @@ export function useEvent() {
const textMode = useRecoilValue(textModeState) const textMode = useRecoilValue(textModeState)
useEffect(() => { useEffect(() => {
initEvent()
}, [currentMenu, canvas, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, dotLineGridSetting, tempGridMode])
const initEvent = () => {
if (!canvas) { if (!canvas) {
return return
} }
@ -33,7 +37,7 @@ export function useEvent() {
canvas?.on('mouse:wheel', wheelEvent) canvas?.on('mouse:wheel', wheelEvent)
addDefaultEvent() addDefaultEvent()
}, [currentMenu, canvas, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, dotLineGridSetting, tempGridMode]) }
const addDefaultEvent = () => { const addDefaultEvent = () => {
//default Event 추가 //default Event 추가
@ -234,8 +238,7 @@ export function useEvent() {
const removeDocumentEvent = (type) => { const removeDocumentEvent = (type) => {
documentEventListeners.current = documentEventListeners.current.filter((event) => { documentEventListeners.current = documentEventListeners.current.filter((event) => {
if (event.eventType === type) { if (event.eventType === type) {
console.log(type) document.removeEventListener(event.eventType, event.handler)
event.element.removeEventListener(type, event.handler)
return false return false
} }
return true return true
@ -248,5 +251,7 @@ export function useEvent() {
removeAllMouseEventListeners, removeAllMouseEventListeners,
removeAllDocumentEventListeners, removeAllDocumentEventListeners,
removeMouseEvent, removeMouseEvent,
removeMouseLine,
initEvent,
} }
} }