외벽선 편집 및 오프셋 추가
This commit is contained in:
parent
d460b3f0ab
commit
dd3797993b
@ -5,16 +5,35 @@ import Eaves from '@/components/floor-plan/modal/eavesGable/type/Eaves'
|
||||
import Gable from '@/components/floor-plan/modal/eavesGable/type/Gable'
|
||||
import WallMerge from '@/components/floor-plan/modal/eavesGable/type/WallMerge'
|
||||
import Shed from '@/components/floor-plan/modal/eavesGable/type/Shed'
|
||||
import { useEavesGableEdit } from '@/hooks/roofcover/useEavesGableEdit'
|
||||
|
||||
export default function EavesGableEdit({ setShowEavesGableEditModal }) {
|
||||
const { getMessage } = useMessage()
|
||||
const [buttonAct, setButtonAct] = useState(1)
|
||||
const buttonMenu = [
|
||||
{ id: 1, name: getMessage('eaves') },
|
||||
{ id: 2, name: getMessage('gable') },
|
||||
{ id: 3, name: getMessage('wall.merge') },
|
||||
{ id: 4, name: getMessage('shed') },
|
||||
]
|
||||
|
||||
const { type, setType, buttonMenu, TYPES, pitchRef, offsetRef, widthRef, radioTypeRef } = useEavesGableEdit()
|
||||
const eavesProps = {
|
||||
pitchRef,
|
||||
offsetRef,
|
||||
widthRef,
|
||||
radioTypeRef,
|
||||
}
|
||||
|
||||
const gableProps = {
|
||||
pitchRef,
|
||||
offsetRef,
|
||||
widthRef,
|
||||
radioTypeRef,
|
||||
}
|
||||
|
||||
const wallMergeProps = {
|
||||
offsetRef,
|
||||
radioTypeRef,
|
||||
}
|
||||
|
||||
const shedProps = {
|
||||
offsetRef,
|
||||
}
|
||||
|
||||
return (
|
||||
<WithDraggable isShow={true} pos={{ x: 50, y: -950 }}>
|
||||
<div className={`modal-pop-wrap r`}>
|
||||
@ -27,17 +46,17 @@ export default function EavesGableEdit({ setShowEavesGableEditModal }) {
|
||||
<div className="modal-body">
|
||||
<div className="modal-btn-wrap">
|
||||
{buttonMenu.map((item) => (
|
||||
<button key={item.id} className={`btn-frame modal ${buttonAct === item.id ? 'act' : ''}`} onClick={() => setButtonAct(item.id)}>
|
||||
<button key={item.id} className={`btn-frame modal ${type === item.type ? 'act' : ''}`} onClick={() => setType(item.type)}>
|
||||
{item.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="properties-setting-wrap outer">
|
||||
<div className="setting-tit">{getMessage('setting')}</div>
|
||||
{buttonAct === 1 && <Eaves />}
|
||||
{buttonAct === 2 && <Gable />}
|
||||
{buttonAct === 3 && <WallMerge />}
|
||||
{buttonAct === 4 && <Shed />}
|
||||
{type === TYPES.EAVES && <Eaves {...eavesProps} />}
|
||||
{type === TYPES.GABLE && <Gable {...gableProps} />}
|
||||
{type === TYPES.WALL_MERGE && <WallMerge {...wallMergeProps} />}
|
||||
{type === TYPES.SHED && <Shed {...shedProps} />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -2,12 +2,12 @@ import { useMessage } from '@/hooks/useMessage'
|
||||
import Image from 'next/image'
|
||||
import { useState } from 'react'
|
||||
|
||||
export default function Eaves() {
|
||||
export default function Eaves({ pitchRef, offsetRef, widthRef, radioTypeRef }) {
|
||||
const { getMessage } = useMessage()
|
||||
const [type, setType] = useState()
|
||||
const [type, setType] = useState('1')
|
||||
const onChange = (e) => {
|
||||
console.log(e)
|
||||
setType(e.target.value)
|
||||
radioTypeRef.current = e.target.value
|
||||
}
|
||||
return (
|
||||
<>
|
||||
@ -17,7 +17,7 @@ export default function Eaves() {
|
||||
{getMessage('slope')}
|
||||
</span>
|
||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||
<input type="text" className="input-origin block" defaultValue={100} />
|
||||
<input type="number" className="input-origin block" defaultValue={4} ref={pitchRef} />
|
||||
</div>
|
||||
<span className="thin">寸</span>
|
||||
</div>
|
||||
@ -26,7 +26,7 @@ export default function Eaves() {
|
||||
{getMessage('offset')}
|
||||
</span>
|
||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||
<input type="text" className="input-origin block" defaultValue={100} />
|
||||
<input type="number" className="input-origin block" defaultValue={500} ref={offsetRef} />
|
||||
</div>
|
||||
<span className="thin">mm</span>
|
||||
</div>
|
||||
@ -63,7 +63,7 @@ export default function Eaves() {
|
||||
<div className="eaves-keraba-th">
|
||||
<div className="outline-form">
|
||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||
<input type="text" className="input-origin block" defaultValue={100} readOnly={type === '1'} />
|
||||
<input type="number" min={0} className="input-origin block" defaultValue={500} ref={widthRef} readOnly={type === '1'} />
|
||||
</div>
|
||||
<span className="thin">mm</span>
|
||||
</div>
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import Image from 'next/image'
|
||||
import { useState } from 'react'
|
||||
|
||||
export default function Gable() {
|
||||
export default function Gable({ pitchRef, offsetRef, widthRef, radioTypeRef }) {
|
||||
const { getMessage } = useMessage()
|
||||
const [type, setType] = useState('1')
|
||||
const onChange = (e) => {
|
||||
setType(e.target.value)
|
||||
radioTypeRef.current = e.target.value
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div className="outline-wrap">
|
||||
@ -11,7 +17,7 @@ export default function Gable() {
|
||||
{getMessage('offset')}
|
||||
</span>
|
||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||
<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>
|
||||
@ -21,12 +27,12 @@ export default function Gable() {
|
||||
<div className="eaves-keraba-item">
|
||||
<div className="eaves-keraba-th">
|
||||
<div className="d-check-radio pop">
|
||||
<input type="radio" name="radio01" id="ra01" />
|
||||
<input type="radio" name="radio01" id="ra01" value="1" checked={type === '1'} onChange={(e) => onChange(e)} />
|
||||
<label htmlFor="ra01">{getMessage('modal.eaves.gable.edit.basic')}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="eaves-keraba-td">
|
||||
<div className="eaves-keraba-ico act">
|
||||
<div className={`eaves-keraba-ico ${type === '1' ? 'act' : ''}`}>
|
||||
<Image src="/static/images/canvas/eaves_icon04.svg" alt="react" width={30} height={30} />
|
||||
</div>
|
||||
</div>
|
||||
@ -34,12 +40,12 @@ export default function Gable() {
|
||||
<div className="eaves-keraba-item">
|
||||
<div className="eaves-keraba-th">
|
||||
<div className="d-check-radio pop">
|
||||
<input type="radio" name="radio01" id="ra02" />
|
||||
<input type="radio" name="radio01" id="ra02" value="2" checked={type === '2'} onChange={(e) => onChange(e)} />
|
||||
<label htmlFor="ra02">{getMessage('jerkinhead')}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="eaves-keraba-td">
|
||||
<div className="eaves-keraba-ico">
|
||||
<div className={`eaves-keraba-ico ${type === '2' ? 'act' : ''}`}>
|
||||
<Image src="/static/images/canvas/eaves_icon09.svg" alt="react" width={30} height={30} />
|
||||
</div>
|
||||
</div>
|
||||
@ -51,7 +57,7 @@ export default function Gable() {
|
||||
{getMessage('slope')}
|
||||
</span>
|
||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||
<input type="text" className="input-origin block" defaultValue={100} />
|
||||
<input type="text" className="input-origin block" defaultValue={4.5} ref={pitchRef} readOnly={type === '1'} />
|
||||
</div>
|
||||
<span className="thin">寸</span>
|
||||
</div>
|
||||
@ -69,7 +75,7 @@ export default function Gable() {
|
||||
{getMessage('offset')}
|
||||
</span>
|
||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||
<input type="text" className="input-origin block" defaultValue={100} />
|
||||
<input type="text" className="input-origin block" defaultValue={800} ref={widthRef} readOnly={type === '1'} />
|
||||
</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 (
|
||||
<>
|
||||
@ -10,7 +10,7 @@ export default function Shed() {
|
||||
{getMessage('offset')}
|
||||
</span>
|
||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||
<input type="text" className="input-origin block" defaultValue={100} />
|
||||
<input type="text" className="input-origin block" ref={offsetRef} defaultValue={300} />
|
||||
</div>
|
||||
<span className="thin">mm</span>
|
||||
</div>
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import Image from 'next/image'
|
||||
import { useState } from 'react'
|
||||
|
||||
export default function WallMerge() {
|
||||
export default function WallMerge({ offsetRef, radioTypeRef }) {
|
||||
const { getMessage } = useMessage()
|
||||
const [type, setType] = useState('1')
|
||||
const onChange = (e) => {
|
||||
setType(e.target.value)
|
||||
radioTypeRef.current = e.target.value
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div className="outline-wrap">
|
||||
@ -11,12 +17,12 @@ export default function WallMerge() {
|
||||
<div className="eaves-keraba-item">
|
||||
<div className="eaves-keraba-th">
|
||||
<div className="d-check-radio pop">
|
||||
<input type="radio" name="radio01" id="ra01" />
|
||||
<input type="radio" name="radio01" id="ra01" value="1" checked={type === '1'} onChange={(e) => onChange(e)} />
|
||||
<label htmlFor="ra01">{getMessage('has.sleeve')}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="eaves-keraba-td">
|
||||
<div className="eaves-keraba-ico act">
|
||||
<div className={`eaves-keraba-ico ${type === '1' ? 'act' : ''}`}>
|
||||
<Image src="/static/images/canvas/eaves_icon06.svg" alt="react" width={30} height={30} />
|
||||
</div>
|
||||
</div>
|
||||
@ -24,12 +30,12 @@ export default function WallMerge() {
|
||||
<div className="eaves-keraba-item">
|
||||
<div className="eaves-keraba-th">
|
||||
<div className="d-check-radio pop">
|
||||
<input type="radio" name="radio01" id="ra02" />
|
||||
<input type="radio" name="radio01" id="ra02" value="2" checked={type === '2'} onChange={(e) => onChange(e)} />
|
||||
<label htmlFor="ra02">{getMessage('has.not.sleeve')}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="eaves-keraba-td">
|
||||
<div className="eaves-keraba-ico">
|
||||
<div className={`eaves-keraba-ico ${type === '2' ? 'act' : ''}`}>
|
||||
<Image src="/static/images/canvas/eaves_icon07.svg" alt="react" width={30} height={30} />
|
||||
</div>
|
||||
</div>
|
||||
@ -41,7 +47,7 @@ export default function WallMerge() {
|
||||
{getMessage('offset')}
|
||||
</span>
|
||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||
<input type="text" className="input-origin block" defaultValue={100} />
|
||||
<input type="text" className="input-origin block" defaultValue={300} ref={offsetRef} readOnly={type === '1'} />
|
||||
</div>
|
||||
<span className="thin">mm</span>
|
||||
</div>
|
||||
|
||||
204
src/hooks/roofcover/useEavesGableEdit.js
Normal file
204
src/hooks/roofcover/useEavesGableEdit.js
Normal file
@ -0,0 +1,204 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { canvasState } from '@/store/canvasAtom'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
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()
|
||||
const { addCanvasMouseEventListener, initEvent } = useEvent()
|
||||
const TYPES = {
|
||||
EAVES: 'eaves',
|
||||
GABLE: 'gable',
|
||||
WALL_MERGE: 'wall.merge',
|
||||
SHED: 'shed',
|
||||
}
|
||||
const [type, setType] = useState(TYPES.EAVES)
|
||||
const typeRef = useRef(TYPES.EAVES)
|
||||
const { removeLine } = useLine()
|
||||
|
||||
const { drawRoofPolygon } = useMode()
|
||||
|
||||
const pitchRef = useRef(null)
|
||||
const offsetRef = useRef(null)
|
||||
const widthRef = useRef(null)
|
||||
const radioTypeRef = useRef('1') // 각 페이지에서 사용하는 radio type
|
||||
|
||||
const buttonMenu = [
|
||||
{ id: 1, name: getMessage('eaves'), type: TYPES.EAVES },
|
||||
{ id: 2, name: getMessage('gable'), type: TYPES.GABLE },
|
||||
{ id: 3, name: getMessage('wall.merge'), type: TYPES.WALL_MERGE },
|
||||
{ id: 4, name: getMessage('shed'), type: TYPES.SHED },
|
||||
]
|
||||
|
||||
useEffect(() => {
|
||||
const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine')
|
||||
wallLines.forEach((wallLine) => {
|
||||
convertPolygonToLines(wallLine)
|
||||
})
|
||||
|
||||
addCanvasMouseEventListener('mouse:over', mouseOverEvent)
|
||||
addCanvasMouseEventListener('mouse:down', mouseDownEvent)
|
||||
|
||||
return () => {
|
||||
wallLines.forEach((wallLine) => {
|
||||
convertLinesToPolygon(wallLine)
|
||||
})
|
||||
initEvent()
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
typeRef.current = type
|
||||
}, [type])
|
||||
|
||||
const mouseOverEvent = (e) => {
|
||||
if (e.target && e.target.name === 'outerLine') {
|
||||
e.target.set({
|
||||
stroke: 'red',
|
||||
})
|
||||
canvas.renderAll()
|
||||
} else {
|
||||
canvas
|
||||
?.getObjects()
|
||||
.filter((obj) => obj.name === 'outerLine')
|
||||
.forEach((line) => {
|
||||
line.set({
|
||||
stroke: 'black',
|
||||
})
|
||||
})
|
||||
}
|
||||
canvas.renderAll()
|
||||
}
|
||||
|
||||
const mouseDownEvent = (e) => {
|
||||
if (!e.target || (e.target && e.target.name !== 'outerLine')) {
|
||||
return
|
||||
}
|
||||
|
||||
const target = e.target
|
||||
|
||||
let attributes = target.get('attributes')
|
||||
|
||||
switch (typeRef.current) {
|
||||
case TYPES.EAVES:
|
||||
if (radioTypeRef.current === '1') {
|
||||
attributes = {
|
||||
type: LINE_TYPE.WALLLINE.EAVES,
|
||||
pitch: pitchRef.current.value,
|
||||
offset: offsetRef.current.value / 10,
|
||||
}
|
||||
} else {
|
||||
attributes = {
|
||||
type: LINE_TYPE.WALLLINE.HIPANDGABLE,
|
||||
pitch: pitchRef.current.value,
|
||||
offset: offsetRef.current.value / 10,
|
||||
width: widthRef.current.value / 10,
|
||||
}
|
||||
}
|
||||
break
|
||||
case TYPES.GABLE:
|
||||
if (radioTypeRef.current === '1') {
|
||||
attributes = {
|
||||
type: LINE_TYPE.WALLLINE.GABLE,
|
||||
offset: offsetRef.current.value / 10,
|
||||
}
|
||||
} else {
|
||||
attributes = {
|
||||
type: LINE_TYPE.WALLLINE.JERKINHEAD,
|
||||
pitch: pitchRef.current.value,
|
||||
offset: offsetRef.current.value / 10,
|
||||
width: widthRef.current.value / 10,
|
||||
}
|
||||
}
|
||||
break
|
||||
case TYPES.WALL_MERGE:
|
||||
if (radioTypeRef.current === '1') {
|
||||
attributes = {
|
||||
type: LINE_TYPE.WALLLINE.WALL,
|
||||
offset: 0,
|
||||
}
|
||||
} else {
|
||||
attributes = {
|
||||
type: LINE_TYPE.WALLLINE.WALL,
|
||||
offset: offsetRef.current.value / 10,
|
||||
}
|
||||
}
|
||||
break
|
||||
case TYPES.SHED:
|
||||
attributes = {
|
||||
type: LINE_TYPE.WALLLINE.SHED,
|
||||
offset: offsetRef.current.value / 10,
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
target.set({
|
||||
attributes,
|
||||
})
|
||||
|
||||
const roofBases = canvas?.getObjects().filter((obj) => obj.name === 'roofBase')
|
||||
|
||||
roofBases.forEach((roof) => {
|
||||
roof.innerLines.forEach((line) => {
|
||||
removeLine(line)
|
||||
})
|
||||
canvas.remove(roof)
|
||||
})
|
||||
|
||||
const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine')
|
||||
|
||||
wallLines.forEach((wallLine) => {
|
||||
const roof = drawRoofPolygon(wallLine)
|
||||
|
||||
canvas?.renderAll()
|
||||
roof.drawHelpLine()
|
||||
})
|
||||
|
||||
wallLines.forEach((wallLine) => {
|
||||
convertPolygonToLines(wallLine)
|
||||
})
|
||||
|
||||
addCanvasMouseEventListener('mouse:over', mouseOverEvent)
|
||||
addCanvasMouseEventListener('mouse:down', mouseDownEvent)
|
||||
}
|
||||
|
||||
// polygon의 lines를 이용해 line으로 변경하기
|
||||
const convertPolygonToLines = (polygon) => {
|
||||
polygon.set({ visible: false })
|
||||
polygon.lines.forEach((line) => {
|
||||
line.set({ visible: true })
|
||||
line.set({ selectable: true })
|
||||
line.set({ strokeWidth: 5 })
|
||||
line.set({ parent: polygon })
|
||||
line.bringToFront()
|
||||
})
|
||||
|
||||
// canvas objects에서 polygon.lines를 제외한 다른 line의 selectable을 false로 변경
|
||||
canvas
|
||||
.getObjects()
|
||||
.filter((obj) => obj.name !== 'outerLine' && obj.type === 'QLine')
|
||||
.forEach((obj) => {
|
||||
obj.set({ selectable: false })
|
||||
})
|
||||
|
||||
canvas?.renderAll()
|
||||
}
|
||||
|
||||
// 다시 다각형으로 변경하기
|
||||
const convertLinesToPolygon = (polygon) => {
|
||||
polygon.set({ visible: true })
|
||||
polygon.lines.forEach((line) => {
|
||||
line.set({ visible: false })
|
||||
line.set({ selectable: false })
|
||||
})
|
||||
|
||||
canvas?.renderAll()
|
||||
}
|
||||
|
||||
return { type, setType, buttonMenu, TYPES, pitchRef, offsetRef, widthRef, radioTypeRef }
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user