Merge branch 'feature/outer-lines' of https://git.jetbrains.space/nalpari/q-cast-iii/qcast-front into dev
This commit is contained in:
commit
a04bd99d35
@ -195,7 +195,12 @@ export default function CanvasMenu(props) {
|
||||
<button className="btn06"></button>
|
||||
</div>
|
||||
<div className="size-control">
|
||||
<button className="control-btn minus"></button>
|
||||
<button
|
||||
className="control-btn minus"
|
||||
onClick={() => {
|
||||
canvas.setZoom(canvas.getZoom() - 0.1)
|
||||
}}
|
||||
></button>
|
||||
<span>{canvasZoom}%</span>
|
||||
<button className="control-btn plus" onClick={handleZoomClear}></button>
|
||||
</div>
|
||||
|
||||
@ -4,15 +4,26 @@ import Eaves from '@/components/floor-plan/modal/roofShape/passivity/Eaves'
|
||||
import Gable from '@/components/floor-plan/modal/roofShape/passivity/Gable'
|
||||
import Shed from '@/components/floor-plan/modal/roofShape/passivity/Shed'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useRoofShapePassivitySetting } from '@/hooks/roofcover/useRoofShapePassivitySetting'
|
||||
|
||||
export default function RoofShapePassivitySetting({ setShowRoofShapePassivitySettingModal }) {
|
||||
const { handleSave, handleConfirm, handleRollback, buttons, type, setType, TYPES, offsetRef, pitchRef } = useRoofShapePassivitySetting()
|
||||
const { getMessage } = useMessage()
|
||||
const [buttonAct, setButtonAct] = useState(1)
|
||||
const buttons = [
|
||||
{ id: 1, name: getMessage('eaves') },
|
||||
{ id: 2, name: getMessage('gable') },
|
||||
{ id: 3, name: getMessage('windage') },
|
||||
]
|
||||
|
||||
const eavesProps = {
|
||||
offsetRef,
|
||||
pitchRef,
|
||||
}
|
||||
|
||||
const gableProps = {
|
||||
offsetRef,
|
||||
pitchRef,
|
||||
}
|
||||
|
||||
const shedProps = {
|
||||
offsetRef,
|
||||
}
|
||||
|
||||
return (
|
||||
<WithDraggable isShow={true} pos={{ x: 50, y: -950 }}>
|
||||
<div className={`modal-pop-wrap xxm`}>
|
||||
@ -25,7 +36,7 @@ export default function RoofShapePassivitySetting({ setShowRoofShapePassivitySet
|
||||
<div className="modal-body">
|
||||
<div className="modal-btn-wrap">
|
||||
{buttons.map((button) => (
|
||||
<button id={button.id} className={`btn-frame modal ${buttonAct === button.id ? 'act' : ''}`} onClick={() => setButtonAct(button.id)}>
|
||||
<button id={button.id} className={`btn-frame modal ${type === button.type ? 'act' : ''}`} onClick={() => setType(button.type)}>
|
||||
{button.name}
|
||||
</button>
|
||||
))}
|
||||
@ -33,17 +44,23 @@ export default function RoofShapePassivitySetting({ setShowRoofShapePassivitySet
|
||||
<div className="modal-bottom-border-bx">
|
||||
<div className="setting-tit">{getMessage('setting')}</div>
|
||||
<div className="discrimination-box">
|
||||
{buttonAct === 1 && <Eaves />}
|
||||
{buttonAct === 2 && <Gable />}
|
||||
{buttonAct === 3 && <Shed />}
|
||||
{type === TYPES.EAVES && <Eaves {...eavesProps} />}
|
||||
{type === TYPES.GABLE && <Gable {...gableProps} />}
|
||||
{type === TYPES.SHED && <Shed {...shedProps} />}
|
||||
</div>
|
||||
<div className="grid-btn-wrap">
|
||||
<button className="btn-frame sub-tab mr5">{getMessage('common.setting.rollback')}</button>
|
||||
<button className="btn-frame sub-tab act">{getMessage('apply')}</button>
|
||||
<button className="btn-frame sub-tab mr5" onClick={handleRollback}>
|
||||
{getMessage('common.setting.rollback')}
|
||||
</button>
|
||||
<button className="btn-frame sub-tab act" onClick={handleConfirm}>
|
||||
{getMessage('apply')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid-btn-wrap">
|
||||
<button className="btn-frame modal act">{getMessage('common.setting.finish')}</button>
|
||||
<button className="btn-frame modal act" onClick={() => handleSave(setShowRoofShapePassivitySettingModal)}>
|
||||
{getMessage('common.setting.finish')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
|
||||
export default function Eaves() {
|
||||
export default function Eaves({ offsetRef, pitchRef }) {
|
||||
const { getMessage } = useMessage()
|
||||
return (
|
||||
<>
|
||||
@ -9,7 +9,7 @@ export default function Eaves() {
|
||||
{getMessage('slope')}
|
||||
</span>
|
||||
<div className="input-grid mr5">
|
||||
<input type="text" className="input-origin block" defaultValue={100} />
|
||||
<input type="text" className="input-origin block" defaultValue={4} ref={pitchRef} />
|
||||
</div>
|
||||
<span className="thin">寸</span>
|
||||
</div>
|
||||
@ -18,7 +18,7 @@ export default function Eaves() {
|
||||
{getMessage('eaves.offset')}
|
||||
</span>
|
||||
<div className="input-grid mr5">
|
||||
<input type="text" className="input-origin block" defaultValue={100} />
|
||||
<input type="text" className="input-origin block" defaultValue={500} ref={offsetRef} />
|
||||
</div>
|
||||
<span className="thin">mm</span>
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
|
||||
export default function Gable() {
|
||||
export default function Gable({ offsetRef, pitchRef }) {
|
||||
const { getMessage } = useMessage()
|
||||
return (
|
||||
<>
|
||||
@ -9,7 +9,7 @@ export default function Gable() {
|
||||
{getMessage('slope')}
|
||||
</span>
|
||||
<div className="input-grid mr5">
|
||||
<input type="text" className="input-origin block" defaultValue={100} />
|
||||
<input type="text" className="input-origin block" defaultValue={4} ref={pitchRef} />
|
||||
</div>
|
||||
<span className="thin">寸</span>
|
||||
</div>
|
||||
@ -18,7 +18,7 @@ export default function Gable() {
|
||||
{getMessage('gable.offset')}
|
||||
</span>
|
||||
<div className="input-grid mr5">
|
||||
<input type="text" className="input-origin block" defaultValue={100} />
|
||||
<input type="text" className="input-origin block" defaultValue={300} ref={offsetRef} />
|
||||
</div>
|
||||
<span className="thin">mm</span>
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
|
||||
export default function Shed() {
|
||||
export default function Shed({ offsetRef }) {
|
||||
const { getMessage } = useMessage()
|
||||
return (
|
||||
<>
|
||||
@ -9,7 +9,7 @@ export default function Shed() {
|
||||
{getMessage('shed.width')}
|
||||
</span>
|
||||
<div className="input-grid mr5">
|
||||
<input type="text" className="input-origin block" defaultValue={100} />
|
||||
<input type="text" className="input-origin block" defaultValue={300} ref={offsetRef} />
|
||||
</div>
|
||||
<span className="thin">mm</span>
|
||||
</div>
|
||||
|
||||
@ -7,9 +7,20 @@ import { useWallLineOffsetSetting } from '@/hooks/roofcover/useWallLineOffsetSet
|
||||
|
||||
export default function WallLineOffsetSetting({ setShowWallLineOffsetSettingModal }) {
|
||||
const { getMessage } = useMessage()
|
||||
const { type, setType, buttonMenu, currentWallLineRef, TYPES, radioTypeRef, arrow1Ref, arrow2Ref, length1Ref, length2Ref, handleSave } =
|
||||
useWallLineOffsetSetting()
|
||||
const [buttonAct, setButtonAct] = useState(1)
|
||||
const {
|
||||
type,
|
||||
setType,
|
||||
buttonMenu,
|
||||
currentWallLineRef,
|
||||
TYPES,
|
||||
radioTypeRef,
|
||||
arrow1Ref,
|
||||
arrow2Ref,
|
||||
length1Ref,
|
||||
length2Ref,
|
||||
handleSave,
|
||||
wallLineEditRef,
|
||||
} = useWallLineOffsetSetting()
|
||||
|
||||
const wallLineProps = {
|
||||
length1Ref,
|
||||
@ -45,7 +56,7 @@ export default function WallLineOffsetSetting({ setShowWallLineOffsetSettingModa
|
||||
</div>
|
||||
<div className="properties-setting-wrap outer">
|
||||
<div className="setting-tit">{getMessage('setting')}</div>
|
||||
{type === TYPES.WALL_LINE_EDIT && <WallLine {...wallLineProps} />}
|
||||
{type === TYPES.WALL_LINE_EDIT && <WallLine ref={wallLineEditRef} {...wallLineProps} />}
|
||||
{type === TYPES.OFFSET && <Offset {...offsetProps} />}
|
||||
</div>
|
||||
<div className="grid-btn-wrap">
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
|
||||
export default function WallLine({ length1Ref, length2Ref, arrow1Ref, arrow2Ref, radioTypeRef, currentWallLineRef }) {
|
||||
export default forwardRef(function WallLine({ length1Ref, length2Ref, arrow1Ref, arrow2Ref, radioTypeRef, currentWallLineRef }, ref) {
|
||||
const { getMessage } = useMessage()
|
||||
const { addDocumentEventListener, initEvent } = useEvent()
|
||||
const [type, setType] = useState(1)
|
||||
@ -10,76 +10,25 @@ export default function WallLine({ length1Ref, length2Ref, arrow1Ref, arrow2Ref,
|
||||
const [arrow2, setArrow2] = useState('up')
|
||||
|
||||
useEffect(() => {
|
||||
addDocumentEventListener('keydown', document, keyDown)
|
||||
|
||||
return () => {
|
||||
initEvent()
|
||||
}
|
||||
}, [])
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
setArrow,
|
||||
}))
|
||||
|
||||
const setArrow = () => {
|
||||
setArrow1(arrow1Ref.current)
|
||||
setArrow2(arrow2Ref.current)
|
||||
}
|
||||
|
||||
const onChange = (e) => {
|
||||
setType(Number(e.target.value))
|
||||
radioTypeRef.current = e.target.value
|
||||
}
|
||||
|
||||
const handleBtnClick = (direction) => {
|
||||
document.dispatchEvent(new KeyboardEvent('keydown', { key: direction }))
|
||||
}
|
||||
|
||||
const keyDown = (e) => {
|
||||
if (currentWallLineRef.current === null) {
|
||||
alert('보조선을 먼저 선택하세요')
|
||||
return
|
||||
}
|
||||
|
||||
const key = e.key
|
||||
|
||||
switch (key) {
|
||||
case 'Down': // IE/Edge에서 사용되는 값
|
||||
case 'ArrowDown': {
|
||||
if (radioTypeRef.current === '1') {
|
||||
setArrow1('down')
|
||||
arrow1Ref.current = 'down'
|
||||
} else {
|
||||
setArrow2('down')
|
||||
arrow2Ref.current = 'down'
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
case 'Up': // IE/Edge에서 사용되는 값
|
||||
case 'ArrowUp':
|
||||
if (radioTypeRef.current === '1') {
|
||||
setArrow1('up')
|
||||
arrow1Ref.current = 'up'
|
||||
} else {
|
||||
setArrow2('up')
|
||||
arrow2Ref.current = 'up'
|
||||
}
|
||||
break
|
||||
case 'Left': // IE/Edge에서 사용되는 값
|
||||
case 'ArrowLeft':
|
||||
if (radioTypeRef.current === '1') {
|
||||
setArrow1('left')
|
||||
arrow1Ref.current = 'left'
|
||||
} else {
|
||||
setArrow2('left')
|
||||
arrow2Ref.current = 'left'
|
||||
}
|
||||
break
|
||||
case 'Right': // IE/Edge에서 사용되는 값
|
||||
case 'ArrowRight':
|
||||
if (radioTypeRef.current === '1') {
|
||||
setArrow1('right')
|
||||
arrow1Ref.current = 'right'
|
||||
} else {
|
||||
setArrow2('right')
|
||||
arrow2Ref.current = 'right'
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="outline-wrap">
|
||||
@ -107,10 +56,10 @@ export default function WallLine({ length1Ref, length2Ref, arrow1Ref, arrow2Ref,
|
||||
<div className="eaves-keraba-td">
|
||||
<div className="outline-form">
|
||||
<div className="grid-direction">
|
||||
<button className={`direction up ${arrow1 === 'up' ? 'act' : ''} `} onClick={() => handleBtnClick('ArrowUp')}></button>
|
||||
<button className={`direction down ${arrow1 === 'down' ? 'act' : ''} `} onClick={() => handleBtnClick('ArrowDown')}></button>
|
||||
<button className={`direction left ${arrow1 === 'left' ? 'act' : ''} `} onClick={() => handleBtnClick('ArrowLeft')}></button>
|
||||
<button className={`direction right ${arrow1 === 'right' ? 'act' : ''} `} onClick={() => handleBtnClick('ArrowRight')}></button>
|
||||
<button className={`direction up ${arrow1 === 'up' ? 'act' : ''} `}></button>
|
||||
<button className={`direction down ${arrow1 === 'down' ? 'act' : ''} `}></button>
|
||||
<button className={`direction left ${arrow1 === 'left' ? 'act' : ''} `}></button>
|
||||
<button className={`direction right ${arrow1 === 'right' ? 'act' : ''} `}></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -141,10 +90,10 @@ export default function WallLine({ length1Ref, length2Ref, arrow1Ref, arrow2Ref,
|
||||
<div className="eaves-keraba-td">
|
||||
<div className="outline-form">
|
||||
<div className="grid-direction">
|
||||
<button className={`direction up ${arrow2 === 'up' ? 'act' : ''} `} onClick={() => handleBtnClick('ArrowUp')}></button>
|
||||
<button className={`direction down ${arrow2 === 'down' ? 'act' : ''} `} onClick={() => handleBtnClick('ArrowDown')}></button>
|
||||
<button className={`direction left ${arrow2 === 'left' ? 'act' : ''} `} onClick={() => handleBtnClick('ArrowLeft')}></button>
|
||||
<button className={`direction right ${arrow2 === 'right' ? 'act' : ''} `} onClick={() => handleBtnClick('ArrowRight')}></button>
|
||||
<button className={`direction up ${arrow2 === 'up' ? 'act' : ''} `}></button>
|
||||
<button className={`direction down ${arrow2 === 'down' ? 'act' : ''} `}></button>
|
||||
<button className={`direction left ${arrow2 === 'left' ? 'act' : ''} `}></button>
|
||||
<button className={`direction right ${arrow2 === 'right' ? 'act' : ''} `}></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -155,4 +104,4 @@ export default function WallLine({ length1Ref, length2Ref, arrow1Ref, arrow2Ref,
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
@ -27,27 +27,16 @@ import { calculateDistance, calculateIntersection, distanceBetweenPoints, findCl
|
||||
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 { addCanvasMouseEventListener, addDocumentEventListener, 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)
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ import { LINE_TYPE } from '@/common/common'
|
||||
import { useLine } from '@/hooks/useLine'
|
||||
import { useMode } from '@/hooks/useMode'
|
||||
|
||||
// 처마.케라바 변경
|
||||
export function useEavesGableEdit() {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
const { getMessage } = useMessage()
|
||||
|
||||
@ -30,6 +30,7 @@ import {
|
||||
import { calculateAngle } from '@/util/qpolygon-utils'
|
||||
import { fabric } from 'fabric'
|
||||
|
||||
//외벽선 그리기
|
||||
export function useOuterLineWall() {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
const { addCanvasMouseEventListener, addDocumentEventListener, removeAllMouseEventListeners, removeAllDocumentEventListeners, removeMouseEvent } =
|
||||
|
||||
@ -7,6 +7,7 @@ import { usePolygon } from '@/hooks/usePolygon'
|
||||
import { useLine } from '@/hooks/useLine'
|
||||
import { outerLinePointsState } from '@/store/outerLineAtom'
|
||||
|
||||
// 외벽선 속성 설정
|
||||
export function usePropertiesSetting() {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
|
||||
@ -19,17 +20,7 @@ export function usePropertiesSetting() {
|
||||
const { removeLine, hideLine } = useLine()
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentObject) {
|
||||
return
|
||||
}
|
||||
if (currentObject.name !== 'outerLine') {
|
||||
return
|
||||
}
|
||||
|
||||
const type = currentObject.attributes?.type
|
||||
|
||||
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||
|
||||
lines.forEach((line) => {
|
||||
const lineType = line.attributes?.type
|
||||
if (!lineType) {
|
||||
@ -39,6 +30,14 @@ export function usePropertiesSetting() {
|
||||
})
|
||||
}
|
||||
})
|
||||
if (!currentObject) {
|
||||
return
|
||||
}
|
||||
if (currentObject.name !== 'outerLine') {
|
||||
return
|
||||
}
|
||||
|
||||
const type = currentObject.attributes?.type
|
||||
|
||||
if (!type) {
|
||||
currentObject.set({
|
||||
@ -46,6 +45,8 @@ export function usePropertiesSetting() {
|
||||
strokeWidth: 4,
|
||||
})
|
||||
}
|
||||
|
||||
canvas.renderAll()
|
||||
}, [currentObject])
|
||||
|
||||
const history = useRef([])
|
||||
@ -106,6 +107,7 @@ export function usePropertiesSetting() {
|
||||
}
|
||||
const lastLine = history.current.pop()
|
||||
|
||||
delete lastLine.attributes
|
||||
lastLine.set({
|
||||
stroke: '#000000',
|
||||
strokeWidth: 4,
|
||||
@ -131,7 +133,7 @@ export function usePropertiesSetting() {
|
||||
hideLine(line)
|
||||
})
|
||||
|
||||
const wall = addPolygonByLines(lines, { name: 'WallLine', fill: 'transparent', stroke: 'black' })
|
||||
const wall = addPolygonByLines(lines, { name: 'wallLine', fill: 'transparent', stroke: 'black' })
|
||||
|
||||
wall.lines = [...lines]
|
||||
|
||||
|
||||
175
src/hooks/roofcover/useRoofShapePassivitySetting.js
Normal file
175
src/hooks/roofcover/useRoofShapePassivitySetting.js
Normal file
@ -0,0 +1,175 @@
|
||||
import { canvasState, currentObjectState } from '@/store/canvasAtom'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useLine } from '@/hooks/useLine'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
import { LINE_TYPE } from '@/common/common'
|
||||
import { useMode } from '@/hooks/useMode'
|
||||
import { usePolygon } from '@/hooks/usePolygon'
|
||||
|
||||
//지붕형상 수동 설정
|
||||
export function useRoofShapePassivitySetting() {
|
||||
const TYPES = {
|
||||
EAVES: 'eaves',
|
||||
GABLE: 'gable',
|
||||
SHED: 'shed',
|
||||
}
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
const { getMessage } = useMessage()
|
||||
const { showLine, hideLine } = useLine()
|
||||
const { addCanvasMouseEventListener, initEvent } = useEvent()
|
||||
const { drawRoofPolygon } = useMode()
|
||||
const { addPolygonByLines } = usePolygon()
|
||||
const currentObject = useRecoilValue(currentObjectState)
|
||||
const offsetRef = useRef(null)
|
||||
const pitchRef = useRef(null)
|
||||
const currentLineRef = useRef(null)
|
||||
|
||||
const history = useRef([])
|
||||
|
||||
const [type, setType] = useState(TYPES.EAVES)
|
||||
|
||||
const buttons = [
|
||||
{ id: 1, name: getMessage('eaves'), type: TYPES.EAVES },
|
||||
{ id: 2, name: getMessage('gable'), type: TYPES.GABLE },
|
||||
{ id: 3, name: getMessage('windage'), type: TYPES.SHED },
|
||||
]
|
||||
|
||||
useEffect(() => {
|
||||
addCanvasMouseEventListener('mouse:down', mouseDown)
|
||||
const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine')
|
||||
canvas.remove(wallLines)
|
||||
|
||||
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||
outerLines.forEach((outerLine, idx) => {
|
||||
if (idx === 0) {
|
||||
currentLineRef.current = outerLine
|
||||
}
|
||||
outerLine.set({ selectable: true })
|
||||
showLine(outerLine)
|
||||
outerLine.bringToFront()
|
||||
})
|
||||
canvas?.renderAll()
|
||||
|
||||
return () => {
|
||||
canvas?.discardActiveObject()
|
||||
initEvent()
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||
lines.forEach((line) => {
|
||||
line.set({
|
||||
stroke: '#000000',
|
||||
strokeWidth: 4,
|
||||
})
|
||||
})
|
||||
if (!currentObject) {
|
||||
return
|
||||
}
|
||||
if (currentObject.name !== 'outerLine') {
|
||||
return
|
||||
}
|
||||
|
||||
currentObject.set({
|
||||
stroke: '#EA10AC',
|
||||
strokeWidth: 4,
|
||||
})
|
||||
|
||||
currentLineRef.current = currentObject
|
||||
|
||||
canvas.renderAll()
|
||||
}, [currentObject])
|
||||
|
||||
const mouseDown = (e) => {
|
||||
if (!e.target) {
|
||||
currentLineRef.current = null
|
||||
return
|
||||
}
|
||||
|
||||
if (e.target && e.target.name === 'outerLine') {
|
||||
currentLineRef.current = e.target
|
||||
}
|
||||
}
|
||||
|
||||
const nextLineFocus = (selectedLine) => {
|
||||
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||
const index = lines.findIndex((line) => line === selectedLine)
|
||||
|
||||
const nextLine = lines[index + 1] || lines[0]
|
||||
canvas.setActiveObject(nextLine)
|
||||
}
|
||||
|
||||
const handleConfirm = () => {
|
||||
if (!currentLineRef.current) {
|
||||
alert('선택된 외곽선이 없습니다.')
|
||||
return
|
||||
}
|
||||
let attributes
|
||||
const offset = Number(offsetRef.current.value) / 10
|
||||
if (type === TYPES.EAVES) {
|
||||
attributes = {
|
||||
type: LINE_TYPE.WALLLINE.EAVES,
|
||||
offset,
|
||||
pitch: pitchRef.current.value,
|
||||
}
|
||||
} else if (type === TYPES.GABLE) {
|
||||
attributes = {
|
||||
type: LINE_TYPE.WALLLINE.GABLE,
|
||||
pitch: pitchRef.current.value,
|
||||
offset,
|
||||
}
|
||||
} else if (type === TYPES.SHED) {
|
||||
attributes = {
|
||||
type: LINE_TYPE.WALLLINE.SHED,
|
||||
offset,
|
||||
}
|
||||
}
|
||||
|
||||
currentLineRef.current.set({
|
||||
attributes,
|
||||
})
|
||||
|
||||
history.current.push(currentLineRef.current)
|
||||
nextLineFocus(currentLineRef.current)
|
||||
}
|
||||
|
||||
const handleRollback = () => {
|
||||
if (history.current.length === 0) {
|
||||
return
|
||||
}
|
||||
const lastLine = history.current.pop()
|
||||
|
||||
delete lastLine.attributes
|
||||
lastLine.set({
|
||||
stroke: '#000000',
|
||||
strokeWidth: 4,
|
||||
})
|
||||
|
||||
canvas.setActiveObject(lastLine)
|
||||
canvas.renderAll()
|
||||
}
|
||||
|
||||
const handleSave = (fn) => {
|
||||
const exceptObjs = canvas.getObjects().filter((obj) => obj.name !== 'outerLine' && obj.parent?.name !== 'outerLine')
|
||||
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||
exceptObjs.forEach((obj) => {
|
||||
canvas.remove(obj)
|
||||
})
|
||||
|
||||
lines.forEach((line) => {
|
||||
hideLine(line)
|
||||
})
|
||||
|
||||
const wall = addPolygonByLines(lines, { name: 'wallLine', fill: 'transparent', stroke: 'black' })
|
||||
|
||||
wall.lines = [...lines]
|
||||
|
||||
const roof = drawRoofPolygon(wall)
|
||||
canvas.renderAll()
|
||||
fn(false)
|
||||
}
|
||||
return { handleSave, handleConfirm, buttons, type, setType, TYPES, offsetRef, pitchRef, handleRollback }
|
||||
}
|
||||
@ -7,6 +7,7 @@ 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)
|
||||
|
||||
@ -5,11 +5,13 @@ import { useMessage } from '@/hooks/useMessage'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
import { useLine } from '@/hooks/useLine'
|
||||
|
||||
// 외벽선 편집 및 오프셋
|
||||
export function useWallLineOffsetSetting() {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
const { showLine, addLine } = useLine()
|
||||
const { getMessage } = useMessage()
|
||||
const { addCanvasMouseEventListener, initEvent } = useEvent()
|
||||
const wallLineEditRef = useRef(null)
|
||||
const length1Ref = useRef(null)
|
||||
const length2Ref = useRef(null)
|
||||
const radioTypeRef = useRef('1')
|
||||
@ -17,6 +19,23 @@ export function useWallLineOffsetSetting() {
|
||||
const arrow1Ref = useRef(null)
|
||||
const arrow2Ref = useRef(null)
|
||||
|
||||
const drawLine = (point1, point2, idx) => {
|
||||
const line = addLine([point1.x, point1.y, point2.x, point2.y], {
|
||||
stroke: 'black',
|
||||
strokeWidth: 4,
|
||||
idx: idx,
|
||||
selectable: true,
|
||||
name: 'outerLine',
|
||||
x1: point1.x,
|
||||
y1: point1.y,
|
||||
x2: point2.x,
|
||||
y2: point2.y,
|
||||
direction: currentWallLineRef.current.direction,
|
||||
})
|
||||
|
||||
line.attributes = { ...currentWallLineRef.current.attributes }
|
||||
}
|
||||
|
||||
const TYPES = {
|
||||
WALL_LINE_EDIT: 'wallLineEdit',
|
||||
OFFSET: 'offset',
|
||||
@ -36,37 +55,114 @@ export function useWallLineOffsetSetting() {
|
||||
showLine(outerLine)
|
||||
})
|
||||
|
||||
const roofs = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
|
||||
|
||||
roofs.forEach((roof) => {
|
||||
roof.innerLines.forEach((innerLine) => {
|
||||
canvas.remove(innerLine)
|
||||
})
|
||||
canvas.remove(roof)
|
||||
//outerLine과 그 text만 남겨둔다.
|
||||
const exceptObjs = canvas.getObjects().filter((obj) => obj.name !== 'outerLine' && obj.parent?.name !== 'outerLine')
|
||||
exceptObjs.forEach((obj) => {
|
||||
canvas.remove(obj)
|
||||
})
|
||||
|
||||
const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine')
|
||||
wallLines.forEach((wallLine) => {
|
||||
canvas.remove(wallLine)
|
||||
})
|
||||
canvas.setActiveObject(outerLines[0])
|
||||
currentWallLineRef.current = outerLines[0]
|
||||
addCircleByLine(currentWallLineRef.current)
|
||||
|
||||
addCanvasMouseEventListener('mouse:down', mouseDown)
|
||||
|
||||
return () => {
|
||||
removeOuterLineEditCircle()
|
||||
canvas.discardActiveObject()
|
||||
initEvent()
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
removeOuterLineEditCircle()
|
||||
addCanvasMouseEventListener('mouse:down', mouseDown)
|
||||
if (type === TYPES.WALL_LINE_EDIT) {
|
||||
addCircleByLine(currentWallLineRef.current)
|
||||
}
|
||||
}, [type])
|
||||
|
||||
const removeOuterLineEditCircle = () => {
|
||||
canvas.remove(...canvas.getObjects().filter((obj) => obj.name === 'outerLineEditCircleStart' || obj.name === 'outerLineEditCircleEnd'))
|
||||
}
|
||||
|
||||
const mouseDown = (e) => {
|
||||
removeOuterLineEditCircle()
|
||||
if (!e.target || (e.target && e.target.name !== 'outerLine')) {
|
||||
currentWallLineRef.current = null
|
||||
return
|
||||
}
|
||||
|
||||
currentWallLineRef.current = e.target
|
||||
if (type === TYPES.WALL_LINE_EDIT) {
|
||||
addCircleByLine(currentWallLineRef.current)
|
||||
}
|
||||
}
|
||||
|
||||
const addCircleByLine = (line) => {
|
||||
const direction = currentWallLineRef.current?.direction
|
||||
let startPoint
|
||||
let endPoint
|
||||
let circle1, circle2
|
||||
|
||||
if (direction === 'top' || direction === 'bottom') {
|
||||
// y1, y2중에 더 작은 값이 startPoint, 더 큰 값이 endPoint
|
||||
if (line.y1 > line.y2) {
|
||||
startPoint = { x: line.x2, y: line.y2 }
|
||||
endPoint = { x: line.x1, y: line.y1 }
|
||||
} else {
|
||||
startPoint = { x: line.x1, y: line.y1 }
|
||||
endPoint = { x: line.x2, y: line.y2 }
|
||||
}
|
||||
arrow1Ref.current = 'down'
|
||||
arrow2Ref.current = 'up'
|
||||
} else {
|
||||
// x1, x2중에 더 작은 값이 startPoint, 더 큰 값이 endPoint
|
||||
if (line.x1 > line.x2) {
|
||||
startPoint = { x: line.x2, y: line.y2 }
|
||||
endPoint = { x: line.x1, y: line.y1 }
|
||||
} else {
|
||||
startPoint = { x: line.x1, y: line.y1 }
|
||||
endPoint = { x: line.x2, y: line.y2 }
|
||||
}
|
||||
arrow1Ref.current = 'right'
|
||||
arrow2Ref.current = 'left'
|
||||
}
|
||||
|
||||
circle1 = new fabric.Circle({
|
||||
radius: 10,
|
||||
fill: 'red',
|
||||
top: startPoint.y - 10,
|
||||
left: startPoint.x - 10,
|
||||
name: 'outerLineEditCircleStart',
|
||||
hasControls: false,
|
||||
hasBorders: false,
|
||||
lockMovementX: true,
|
||||
lockMovementY: true,
|
||||
})
|
||||
|
||||
circle2 = new fabric.Circle({
|
||||
radius: 10,
|
||||
fill: 'blue',
|
||||
top: endPoint.y - 10,
|
||||
left: endPoint.x - 10,
|
||||
name: 'outerLineEditCircleEnd',
|
||||
hasControls: false,
|
||||
hasBorders: false,
|
||||
lockMovementX: true,
|
||||
lockMovementY: true,
|
||||
})
|
||||
|
||||
wallLineEditRef.current.setArrow()
|
||||
canvas.add(circle1)
|
||||
canvas.add(circle2)
|
||||
}
|
||||
|
||||
const handleSave = () => {
|
||||
if (currentWallLineRef.current === null) {
|
||||
alert('보조선을 먼저 선택하세요')
|
||||
return
|
||||
}
|
||||
switch (type) {
|
||||
case TYPES.WALL_LINE_EDIT:
|
||||
handleWallLineEditSave()
|
||||
@ -78,19 +174,65 @@ export function useWallLineOffsetSetting() {
|
||||
}
|
||||
|
||||
const handleWallLineEditSave = () => {
|
||||
const direction = currentWallLineRef.current.direction
|
||||
let canDirections = direction === 'left' || direction === 'right' ? ['up', 'down'] : ['left', 'right']
|
||||
if (radioTypeRef === 1) {
|
||||
if (!canDirections.includes(arrow1Ref.current)) {
|
||||
alert('방향을 다시 선택하세요')
|
||||
return
|
||||
const startPoint = canvas
|
||||
.getObjects()
|
||||
.filter((obj) => obj.name === 'outerLineEditCircleStart')
|
||||
.map((obj) => {
|
||||
return {
|
||||
x: obj.left + obj.radius,
|
||||
y: obj.top + obj.radius,
|
||||
}
|
||||
})[0]
|
||||
const endPoint = canvas
|
||||
.getObjects()
|
||||
.filter((obj) => obj.name === 'outerLineEditCircleEnd')
|
||||
.map((obj) => {
|
||||
return {
|
||||
x: obj.left + obj.radius,
|
||||
y: obj.top + obj.radius,
|
||||
}
|
||||
})[0]
|
||||
const length = Number(length1Ref.current.value) / 10
|
||||
const currentIdx = currentWallLineRef.current.idx
|
||||
let point1, point2, point3
|
||||
if (radioTypeRef.current === '1') {
|
||||
// 1지점 선택시 방향은 down, right만 가능
|
||||
if (arrow1Ref.current === 'down') {
|
||||
point1 = { x: startPoint.x, y: startPoint.y }
|
||||
point2 = { x: startPoint.x, y: startPoint.y + length }
|
||||
point3 = { x: endPoint.x, y: endPoint.y }
|
||||
} else {
|
||||
point1 = { x: startPoint.x, y: startPoint.y }
|
||||
point2 = { x: startPoint.x + length, y: startPoint.y }
|
||||
point3 = { x: endPoint.x, y: endPoint.y }
|
||||
}
|
||||
} else {
|
||||
if (!canDirections.includes(arrow2Ref.current)) {
|
||||
alert('방향을 다시 선택하세요')
|
||||
return
|
||||
// 2지점일 경우 방향은 up, left만 가능
|
||||
if (arrow2Ref.current === 'up') {
|
||||
point1 = { x: startPoint.x, y: startPoint.y }
|
||||
point2 = { x: startPoint.x, y: startPoint.y - length }
|
||||
point3 = { x: endPoint.x, y: endPoint.y }
|
||||
} else {
|
||||
point1 = { x: startPoint.x, y: startPoint.y }
|
||||
point2 = { x: startPoint.x - length, y: startPoint.y }
|
||||
point3 = { x: endPoint.x, y: endPoint.y }
|
||||
}
|
||||
}
|
||||
|
||||
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||
outerLines.forEach((outerLine) => {
|
||||
if (outerLine.idx >= currentIdx + 1) {
|
||||
outerLine.idx = outerLine.idx + 1
|
||||
}
|
||||
})
|
||||
|
||||
drawLine(point1, point2, currentIdx)
|
||||
drawLine(point2, point3, currentIdx + 1)
|
||||
|
||||
removeOuterLineEditCircle()
|
||||
canvas.remove(currentWallLineRef.current)
|
||||
currentWallLineRef.current = null
|
||||
canvas.renderAll()
|
||||
}
|
||||
|
||||
const handleOffsetSave = () => {
|
||||
@ -103,26 +245,100 @@ export function useWallLineOffsetSetting() {
|
||||
}
|
||||
|
||||
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||
|
||||
const idx = currentWallLineRef.current.idx
|
||||
const prevLine = outerLines.find((line) => (line.idx === idx - 1 < 0 ? outerLines.length - 1 : idx - 1))
|
||||
const prevIdx = idx - 1 <= 0 ? outerLines.length : idx - 1
|
||||
const nextIdx = idx + 1 > outerLines.length ? 1 : idx + 1
|
||||
|
||||
const currentLine = currentWallLineRef.current
|
||||
const nextLine = outerLines.find((line) => (line.idx === idx + 1 > outerLines.length - 1 ? 0 : idx + 1))
|
||||
const prevLine = outerLines.find((line) => line.idx === prevIdx)
|
||||
const nextLine = outerLines.find((line) => line.idx === nextIdx)
|
||||
|
||||
const length = length1Ref.current.value / 10
|
||||
|
||||
switch (arrow1Ref.current) {
|
||||
case 'up': {
|
||||
console.log(prevLine, currentLine, nextLine)
|
||||
const currentLineY = Math.floor(Math.max(currentLine.y1, currentLine.y2))
|
||||
currentLine.set({ y1: currentLineY - length, y2: currentLineY - length })
|
||||
|
||||
if (Math.abs(currentLineY - prevLine.y1) < 2) {
|
||||
prevLine.set({ y1: currentLineY - length })
|
||||
} else {
|
||||
prevLine.set({ y2: currentLineY - length })
|
||||
}
|
||||
if (Math.abs(currentLineY - nextLine.y1) < 2) {
|
||||
nextLine.set({ y1: currentLineY - length })
|
||||
} else {
|
||||
nextLine.set({ y2: currentLineY - length })
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
case 'down': {
|
||||
const currentLineY = Math.floor(Math.max(currentLine.y1, currentLine.y2))
|
||||
currentLine.set({ y1: currentLineY + length, y2: currentLineY + length })
|
||||
|
||||
if (Math.abs(currentLineY - prevLine.y1) < 2) {
|
||||
prevLine.set({ y1: currentLineY + length })
|
||||
} else {
|
||||
prevLine.set({ y2: currentLineY + length })
|
||||
}
|
||||
if (Math.abs(currentLineY - nextLine.y1) < 2) {
|
||||
nextLine.set({ y1: currentLineY + length })
|
||||
} else {
|
||||
nextLine.set({ y2: currentLineY + length })
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'left': {
|
||||
const currentLineX = Math.floor(Math.max(currentLine.x1, currentLine.x2))
|
||||
currentLine.set({ x1: currentLineX - length, x2: currentLineX - length })
|
||||
|
||||
if (Math.abs(currentLineX - prevLine.x1) < 2) {
|
||||
prevLine.set({ x1: currentLineX - length })
|
||||
} else {
|
||||
prevLine.set({ x2: currentLineX - length })
|
||||
}
|
||||
if (Math.abs(currentLineX - nextLine.x1) < 2) {
|
||||
nextLine.set({ x1: currentLineX - length })
|
||||
} else {
|
||||
nextLine.set({ x2: currentLineX - length })
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'right': {
|
||||
const currentLineX = Math.floor(Math.max(currentLine.x1, currentLine.x2))
|
||||
currentLine.set({ x1: currentLineX + length, x2: currentLineX + length })
|
||||
|
||||
if (Math.abs(currentLineX - prevLine.x1) < 2) {
|
||||
prevLine.set({ x1: currentLineX + length })
|
||||
} else {
|
||||
prevLine.set({ x2: currentLineX + length })
|
||||
}
|
||||
if (Math.abs(currentLineX - nextLine.x1) < 2) {
|
||||
nextLine.set({ x1: currentLineX + length })
|
||||
} else {
|
||||
nextLine.set({ x2: currentLineX + length })
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
canvas.renderAll()
|
||||
}
|
||||
|
||||
return { type, setType, buttonMenu, TYPES, length1Ref, length2Ref, radioTypeRef, currentWallLineRef, arrow1Ref, arrow2Ref, handleSave }
|
||||
return {
|
||||
type,
|
||||
setType,
|
||||
buttonMenu,
|
||||
TYPES,
|
||||
length1Ref,
|
||||
length2Ref,
|
||||
radioTypeRef,
|
||||
currentWallLineRef,
|
||||
arrow1Ref,
|
||||
arrow2Ref,
|
||||
handleSave,
|
||||
wallLineEditRef,
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user