- 외벽선 그리기 작업중
This commit is contained in:
parent
7fc84937cf
commit
c1fd6087cd
@ -1,19 +1,22 @@
|
||||
export const STEP = {
|
||||
export const MENU = {
|
||||
INITIAL_CANVAS_SETTING: 'initialCanvasSetting', // 배치면 초기설정
|
||||
ROOF_COVERING: {
|
||||
EXTERIOR_WALL_LINE: 'exteriorWallLine', // 외벽선 그리기
|
||||
ROOF_SHAPE_SETTINGS: 'roofShapeSettings', // 지붕형상 설정
|
||||
ROOF_SHAPE_EDITING: 'roofShapeEditing', // 지붕형상 편집
|
||||
HELP_LINE_DRAWING: 'helpLineDrawing', // 보조선 그리기
|
||||
DEFAULT: 'roofCoveringDefault', // 아무것도 선택 안할 경우
|
||||
}, // 지붕덮개
|
||||
BATCH_CANVAS: {
|
||||
BATCH_DRAWING: 'batchDrawing', // 배치면 그리기
|
||||
SURFACE_SHAPE_BATCH: 'surfaceShapeBatch', // 면형상 배치
|
||||
OBJECT_BATCH: 'objectBatch', // 오브젝트 배치
|
||||
DEFAULT: 'batchCanvasDefault', // default
|
||||
}, // 배치면
|
||||
MODULE_CIRCUIT_SETTING: {
|
||||
BASIC_SETTING: 'basicSetting', // 기본설정
|
||||
CIRCUIT_TRESTLE_SETTING: 'circuitTrestleSetting', // 회로가대설정
|
||||
DEFAULT: 'moduleCircuitSettingDefault',
|
||||
}, // 모듈회로구성
|
||||
ESTIMATE: 'estimate', // todo 견적서
|
||||
POWER_GENERATION_SIMULATION: 'powerGenerationSimulation', // todo 발전 시뮬레이션
|
||||
|
||||
@ -1,45 +1,47 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from "react"
|
||||
import CanvasFrame from "./CanvasFrame";
|
||||
import { useState } from 'react'
|
||||
import CanvasFrame from './CanvasFrame'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { currentMenuState, stepState } from '@/store/canvasAtom'
|
||||
|
||||
export default function CanvasLayout () {
|
||||
const [plans, setPlans] = useState([{ id: 0, name: 'Plan 1' }, { id: 1, name: 'Plan 2' }, { id: 2, name: 'Plan 3' }]);
|
||||
const [idxNum, setIdxNum] = useState(null);
|
||||
export default function CanvasLayout() {
|
||||
const [plans, setPlans] = useState([
|
||||
{ id: 0, name: 'Plan 1' },
|
||||
{ id: 1, name: 'Plan 2' },
|
||||
{ id: 2, name: 'Plan 3' },
|
||||
])
|
||||
const [idxNum, setIdxNum] = useState(null)
|
||||
|
||||
const onClickPlane = (num) => {
|
||||
setIdxNum(num);
|
||||
}
|
||||
const onClickPlane = (num) => {
|
||||
setIdxNum(num)
|
||||
}
|
||||
|
||||
const handleDeletePlan = (e, id) => {
|
||||
e.stopPropagation(); // 이벤트 버블링 방지
|
||||
setPlans(plans.filter(plan => plan.id !== id)); // 삭제할 아이디와 다른 아이템만 남김
|
||||
}
|
||||
const handleDeletePlan = (e, id) => {
|
||||
e.stopPropagation() // 이벤트 버블링 방지
|
||||
setPlans(plans.filter((plan) => plan.id !== id)) // 삭제할 아이디와 다른 아이템만 남김
|
||||
}
|
||||
|
||||
const addNewPlan = () => {
|
||||
setPlans([...plans, { id: plans.length, name: `Plan ${plans.length + 1}` }]);
|
||||
}
|
||||
const addNewPlan = () => {
|
||||
setPlans([...plans, { id: plans.length, name: `Plan ${plans.length + 1}` }])
|
||||
}
|
||||
|
||||
return(
|
||||
<div className="canvas-layout">
|
||||
<div className="canvas-page-list">
|
||||
<div className="canvas-plane-wrap">
|
||||
{plans.map((plan, idx) => (
|
||||
<button
|
||||
key={plan.id}
|
||||
className={`canvas-page-box ${idx === idxNum ? 'on' : ''}`}
|
||||
onClick={() => onClickPlane(idx)}
|
||||
>
|
||||
<span>{plan.name}</span>
|
||||
<i className="close" onClick={(e) => handleDeletePlan(e, plan.id)}></i>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<button className="plane-add" onClick={addNewPlan}>
|
||||
<span></span>
|
||||
</button>
|
||||
</div>
|
||||
<CanvasFrame/>
|
||||
return (
|
||||
<div className="canvas-layout">
|
||||
<div className="canvas-page-list">
|
||||
<div className="canvas-plane-wrap">
|
||||
{plans.map((plan, idx) => (
|
||||
<button key={plan.id} className={`canvas-page-box ${idx === idxNum ? 'on' : ''}`} onClick={() => onClickPlane(idx)}>
|
||||
<span>{plan.name}</span>
|
||||
<i className="close" onClick={(e) => handleDeletePlan(e, plan.id)}></i>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<button className="plane-add" onClick={addNewPlan}>
|
||||
<span></span>
|
||||
</button>
|
||||
</div>
|
||||
<CanvasFrame />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
'use client'
|
||||
import { useState } from 'react'
|
||||
import MenuDepth01 from './MenuDepth01'
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { modalState } from '@/store/modalAtom'
|
||||
import QSelectBox from '@/components/common/select/QSelectBox'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { currentMenuState } from '@/store/canvasAtom'
|
||||
import { MENU } from '@/common/common'
|
||||
import RoofCoveringMenu from '@/components/floor-plan/RoofCoveringMenu'
|
||||
|
||||
export default function CanvasMenu() {
|
||||
const [modalOption, setModalOption] = useRecoilState(modalState) //modal 열림닫힘 state
|
||||
@ -12,34 +14,37 @@ export default function CanvasMenu() {
|
||||
const [vertical, setVertical] = useState(true)
|
||||
const { getMessage } = useMessage()
|
||||
const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }]
|
||||
const onClickNav = (number) => {
|
||||
setMenuNumber(number)
|
||||
if (menuNumber === number) {
|
||||
setMenuNumber(null)
|
||||
}
|
||||
const [currentMenu, setCurrentMenu] = useRecoilState(currentMenuState)
|
||||
|
||||
const onClickNav = (menu) => {
|
||||
setCurrentMenu(menu)
|
||||
}
|
||||
return (
|
||||
<div className={`canvas-menu-wrap ${menuNumber === 2 || menuNumber === 3 || menuNumber === 4 ? 'active' : ''}`}>
|
||||
<div
|
||||
className={`canvas-menu-wrap ${Object.values(MENU.ROOF_COVERING).includes(currentMenu) || menuNumber === 3 || menuNumber === 4 ? 'active' : ''}`}
|
||||
>
|
||||
<div className="canvas-menu-inner">
|
||||
<ul className="canvas-menu-list">
|
||||
<li className={`canvas-menu-item ${menuNumber === 0 ? 'active' : ''}`} onClick={() => onClickNav(0)}>
|
||||
<li className={`canvas-menu-item `} onClick={() => onClickNav(1)}>
|
||||
<button>
|
||||
<span className="menu-icon con00"></span>
|
||||
{getMessage('plan.menu.plan.drawing')}
|
||||
</button>
|
||||
</li>
|
||||
<li className={`canvas-menu-item ${menuNumber === 1 ? 'active' : ''}`} onClick={() => onClickNav(1)}>
|
||||
<button>
|
||||
<span className="menu-icon con01"></span>
|
||||
{getMessage('plan.menu.placement.surface.initial.setting')}
|
||||
</button>
|
||||
</li>
|
||||
{
|
||||
<li
|
||||
className={`canvas-menu-item ${currentMenu === MENU.INITIAL_CANVAS_SETTING ? 'active' : ''}`}
|
||||
onClick={() => onClickNav(MENU.INITIAL_CANVAS_SETTING)}
|
||||
>
|
||||
<button>
|
||||
<span className="menu-icon con01"></span>
|
||||
{getMessage('plan.menu.placement.surface.initial.setting')}
|
||||
</button>
|
||||
</li>
|
||||
}
|
||||
<li
|
||||
className={`canvas-menu-item ${menuNumber === 2 ? 'active' : ''}`}
|
||||
onClick={() => {
|
||||
setModalOption({ ...modalOption, outerwall: true })
|
||||
onClickNav(2)
|
||||
}}
|
||||
className={`canvas-menu-item ${Object.values(MENU.ROOF_COVERING).includes(currentMenu) ? 'active' : ''}`}
|
||||
onClick={() => onClickNav(MENU.ROOF_COVERING.DEFAULT)}
|
||||
>
|
||||
<button>
|
||||
<span className="menu-icon con02"></span>
|
||||
@ -142,10 +147,13 @@ export default function CanvasMenu() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={`canvas-depth2-wrap ${menuNumber === 2 || menuNumber === 3 || menuNumber === 4 ? 'active' : ''}`}>
|
||||
{menuNumber === 2 && <MenuDepth01 />}
|
||||
<div
|
||||
className={`canvas-depth2-wrap ${Object.values(MENU.ROOF_COVERING).includes(currentMenu) || menuNumber === 3 || menuNumber === 4 ? 'active' : ''}`}
|
||||
>
|
||||
{Object.values(MENU.ROOF_COVERING).includes(currentMenu) && <RoofCoveringMenu />}
|
||||
{/*{menuNumber === 2 && <MenuDepth01 />}
|
||||
{menuNumber === 3 && <MenuDepth01 />}
|
||||
{menuNumber === 4 && <MenuDepth01 />}
|
||||
{menuNumber === 4 && <MenuDepth01 />}*/}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
54
src/components/floor-plan/RoofCoveringMenu.jsx
Normal file
54
src/components/floor-plan/RoofCoveringMenu.jsx
Normal file
@ -0,0 +1,54 @@
|
||||
'use client'
|
||||
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useRecoilState, useSetRecoilState } from 'recoil'
|
||||
import { currentMenuState } from '@/store/canvasAtom'
|
||||
import { MENU } from '@/common/common'
|
||||
import { modalState } from '@/store/modalAtom'
|
||||
import { ToggleonMouse } from '@/components/header/Header'
|
||||
|
||||
export default function RoofCoveringMenu() {
|
||||
const { getMessage } = useMessage()
|
||||
const [currentMenu, setCurrentMenu] = useRecoilState(currentMenuState)
|
||||
|
||||
const setModalState = useSetRecoilState(modalState)
|
||||
|
||||
const onClickNav = (menu) => {
|
||||
setCurrentMenu(menu)
|
||||
if (menu === MENU.ROOF_COVERING.EXTERIOR_WALL_LINE) {
|
||||
setModalState((prev) => ({ ...prev, outerwall: true }))
|
||||
} else {
|
||||
setModalState((prev) => ({ ...prev, outerwall: false }))
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="canvas-depth2-inner">
|
||||
<ul className="canvas-depth2-list">
|
||||
<li className={`canvas-depth2-item ${currentMenu === MENU.ROOF_COVERING.EXTERIOR_WALL_LINE ? 'active' : ''}`}>
|
||||
<button onClick={(e) => onClickNav(MENU.ROOF_COVERING.EXTERIOR_WALL_LINE)}>{getMessage('plan.menu.root.cover.outline.drawing')}</button>
|
||||
</li>
|
||||
<li className={`canvas-depth2-item ${currentMenu === MENU.ROOF_COVERING.ROOF_SHAPE_SETTINGS ? 'active' : ''}`}>
|
||||
<button onClick={(e) => onClickNav(MENU.ROOF_COVERING.ROOF_SHAPE_SETTINGS)}>{getMessage('plan.menu.root.cover.roof.setting')}</button>
|
||||
</li>
|
||||
<li className={`canvas-depth2-item ${currentMenu === MENU.ROOF_COVERING.ROOF_SHAPE_EDITING ? 'active' : ''}`}>
|
||||
<button onClick={(e) => onClickNav(MENU.ROOF_COVERING.ROOF_SHAPE_EDITING)}>{getMessage('plan.menu.root.cover.roof.edit')}</button>
|
||||
</li>
|
||||
<li className={`canvas-depth2-item ${currentMenu === MENU.ROOF_COVERING.HELP_LINE_DRAWING ? 'active' : ''}`}>
|
||||
<button onClick={(e) => onClickNav(MENU.ROOF_COVERING.HELP_LINE_DRAWING)}>{getMessage('plan.menu.root.cover.sub.line')}</button>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="canvas-depth2-btn-list">
|
||||
<li className="depth2-btn-box" onMouseEnter={(e) => ToggleonMouse(e, 'add', 'ul')} onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'ul')}>
|
||||
<button>{getMessage('plan.menu.estimate.roof.alloc')}</button>
|
||||
</li>
|
||||
<li className="depth2-btn-box" onMouseEnter={(e) => ToggleonMouse(e, 'add', 'ul')} onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'ul')}>
|
||||
<button>屋根材の設定と変更</button>
|
||||
</li>
|
||||
<li className="depth2-btn-box" onMouseEnter={(e) => ToggleonMouse(e, 'add', 'ul')} onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'ul')}>
|
||||
<button>屋根面全体削除</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -1,68 +1,239 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import WithDraggable from '@/components/common/draggable/withDraggable'
|
||||
import { modalState } from '@/store/modalAtom'
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
import { canvasState } from '@/store/canvasAtom'
|
||||
import {
|
||||
OUTER_LINE_TYPE,
|
||||
outerLineArrow1State,
|
||||
outerLineArrow2State,
|
||||
outerLineLength1State,
|
||||
outerLineLength2State,
|
||||
outerLinePointsState,
|
||||
outerLineTypeState,
|
||||
} from '@/store/outerLineAtom'
|
||||
import { QLine } from '@/components/fabric/QLine'
|
||||
|
||||
export default function OuterLineWall() {
|
||||
const [modalOption, setModalOption] = useRecoilState(modalState) //modal 열림닫힘 state
|
||||
const [buttonAct, setButtonAct] = useState(1)
|
||||
const [close, setClose] = useState(false)
|
||||
const { getMessage } = useMessage()
|
||||
const HandleClickClose = () => {
|
||||
setClose(true)
|
||||
setTimeout(() => {
|
||||
setModalOption({ ...modalOption, outerwall: false })
|
||||
setClose(false)
|
||||
}, 180)
|
||||
const { addCanvasMouseEventListener, addDocumentEventListener } = useEvent()
|
||||
const length1Ref = useRef(null)
|
||||
const length2Ref = useRef(null)
|
||||
const [length1, setLength1] = useRecoilState(outerLineLength1State)
|
||||
const [length2, setLength2] = useRecoilState(outerLineLength2State)
|
||||
const [arrow1, setArrow1] = useRecoilState(outerLineArrow1State)
|
||||
const [arrow2, setArrow2] = useRecoilState(outerLineArrow2State)
|
||||
const [points, setPoints] = useRecoilState(outerLinePointsState)
|
||||
const [type, setType] = useRecoilState(outerLineTypeState)
|
||||
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
|
||||
useEffect(() => {
|
||||
addCanvasMouseEventListener('mouse:down', mouseDown)
|
||||
addDocumentEventListener('keydown', document, keydown)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
clear()
|
||||
}, [type])
|
||||
|
||||
const clear = () => {
|
||||
setLength1(0)
|
||||
setArrow1('')
|
||||
}
|
||||
|
||||
const mouseDown = (e) => {
|
||||
const pointer = canvas.getPointer(e.e)
|
||||
|
||||
setPoints((prev) => [...prev, pointer])
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
canvas
|
||||
?.getObjects()
|
||||
.filter((obj) => obj.name === 'outerLine')
|
||||
.forEach((obj) => {
|
||||
canvas?.remove(obj)
|
||||
})
|
||||
canvas?.remove(canvas?.getObjects().find((obj) => obj.name === 'startPoint'))
|
||||
if (points.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
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: 'startPoint',
|
||||
})
|
||||
|
||||
canvas?.add(point)
|
||||
} else {
|
||||
points.forEach((point, idx) => {
|
||||
if (idx === 0) {
|
||||
return
|
||||
}
|
||||
drawLine(points[idx - 1], point)
|
||||
})
|
||||
}
|
||||
}, [points])
|
||||
|
||||
const drawLine = (point1, point2) => {
|
||||
const line = new QLine([point1.x, point1.y, point2.x, point2.y], {
|
||||
stroke: 'black',
|
||||
strokeWidth: 1,
|
||||
selectable: false,
|
||||
name: 'outerLine',
|
||||
})
|
||||
|
||||
line.setViewLengthText(true)
|
||||
|
||||
canvas?.add(line)
|
||||
}
|
||||
|
||||
const keydown = (e) => {
|
||||
const key = e.key
|
||||
|
||||
const lengthNum = Number(length1Ref.current.value)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 일변전으로 돌아가기
|
||||
*/
|
||||
const handleRollback = () => {
|
||||
//points의 마지막 요소를 제거
|
||||
setPoints((prev) => prev.slice(0, prev.length - 1))
|
||||
}
|
||||
|
||||
const handleClickClose = () => {
|
||||
setModalOption({ ...modalOption, outerwall: false })
|
||||
}
|
||||
|
||||
const handleFix = () => {}
|
||||
return (
|
||||
<WithDraggable isShow={true}>
|
||||
<div className={`modal-pop-wrap ssm ${modalOption.outerwall ? 'mount' : ''} ${close ? 'unmount' : ''} `}>
|
||||
<div className={`modal-pop-wrap ssm ${modalOption.outerwall ? 'mount' : ''} `}>
|
||||
<div className="modal-head">
|
||||
<h1 className="title">{getMessage('modal.cover.outline.drawing')}</h1>
|
||||
<button className="modal-close" onClick={HandleClickClose}>
|
||||
<button className="modal-close" onClick={handleClickClose}>
|
||||
닫기
|
||||
</button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<div className="modal-btn-wrap">
|
||||
<button className={`btn-frame modal ${buttonAct === 1 ? 'act' : ''}`} onClick={() => setButtonAct(1)}>
|
||||
<button
|
||||
className={`btn-frame modal ${type === OUTER_LINE_TYPE.OUTER_LINE ? 'act' : ''}`}
|
||||
onClick={() => setType(OUTER_LINE_TYPE.OUTER_LINE)}
|
||||
>
|
||||
{getMessage('modal.cover.outline')}
|
||||
</button>
|
||||
|
||||
<button className={`btn-frame modal ${buttonAct === 2 ? 'act' : ''}`} onClick={() => setButtonAct(2)}>
|
||||
<button
|
||||
className={`btn-frame modal ${type === OUTER_LINE_TYPE.RIGHT_ANGLE ? 'act' : ''}`}
|
||||
onClick={() => setType(OUTER_LINE_TYPE.RIGHT_ANGLE)}
|
||||
>
|
||||
{getMessage('modal.cover.outline.right.angle')}
|
||||
</button>
|
||||
<button className={`btn-frame modal ${buttonAct === 3 ? 'act' : ''}`} onClick={() => setButtonAct(3)}>
|
||||
<button
|
||||
className={`btn-frame modal ${type === OUTER_LINE_TYPE.LEE_GUBAE ? 'act' : ''}`}
|
||||
onClick={() => setType(OUTER_LINE_TYPE.LEE_GUBAE)}
|
||||
>
|
||||
{getMessage('modal.cover.outline2')}
|
||||
</button>
|
||||
<button className={`btn-frame modal ${buttonAct === 4 ? 'act' : ''}`} onClick={() => setButtonAct(4)}>
|
||||
<button className={`btn-frame modal ${type === OUTER_LINE_TYPE.ANGLE ? 'act' : ''}`} onClick={() => setType(OUTER_LINE_TYPE.ANGLE)}>
|
||||
{getMessage('modal.cover.outline.angle')}
|
||||
</button>
|
||||
<button className={`btn-frame modal ${buttonAct === 5 ? 'act' : ''}`} onClick={() => setButtonAct(5)}>
|
||||
<button
|
||||
className={`btn-frame modal ${type === OUTER_LINE_TYPE.DIAGONAL_LINE ? 'act' : ''}`}
|
||||
onClick={() => setType(OUTER_LINE_TYPE.DIAGONAL_LINE)}
|
||||
>
|
||||
{getMessage('modal.cover.outline.diagonal')}
|
||||
</button>
|
||||
</div>
|
||||
<div className="modal-check-btn-wrap">
|
||||
<h3 className="check-wrap-title">{getMessage('modal.cover.outline.setting')}</h3>
|
||||
<div className="outer-line-wrap">
|
||||
<div className="form-input">
|
||||
<label htmlFor="">{getMessage('modal.cover.outline.length')}</label>
|
||||
<input type="text" className="input-origin block" placeholder="320mm" />
|
||||
{type === OUTER_LINE_TYPE.OUTER_LINE ? (
|
||||
<div className="outer-line-wrap">
|
||||
<div className="form-input">
|
||||
<label htmlFor="">{getMessage('modal.cover.outline.length')}</label>
|
||||
<input
|
||||
type="text"
|
||||
className="input-origin block"
|
||||
value={length1}
|
||||
ref={length1Ref}
|
||||
onChange={(e) => {
|
||||
setLength1(e.target.value.replace(/[^-0-9]/g, ''))
|
||||
}}
|
||||
placeholder="3000"
|
||||
/>
|
||||
</div>
|
||||
<div className="form-input">
|
||||
<label htmlFor="">{getMessage('modal.cover.outline.arrow')}</label>
|
||||
<input type="text" value={arrow1} className="input-origin block" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-input">
|
||||
<label htmlFor="">{getMessage('modal.cover.outline.arrow')}</label>
|
||||
<input type="text" className="input-origin block" placeholder="320mm" />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<div className="flex-check-box for2 btn">
|
||||
<button className="arr-btn dark">
|
||||
<button className="arr-btn dark" onClick={handleFix}>
|
||||
<span>{getMessage('modal.cover.outline.fix')}</span>
|
||||
</button>
|
||||
<button className="arr-btn dark act">
|
||||
<button className="arr-btn dark act" onClick={handleRollback}>
|
||||
<span>{getMessage('modal.cover.outline.rollback')}</span>
|
||||
</button>
|
||||
<button className="arr-btn dark">
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { canvasState, stepState } from '@/store/canvasAtom'
|
||||
import { canvasState, currentMenuState } from '@/store/canvasAtom'
|
||||
import { fabric } from 'fabric'
|
||||
|
||||
export function useEvent() {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
const step = useRecoilValue(stepState)
|
||||
const currentMenu = useRecoilValue(currentMenuState)
|
||||
const keyboardEventListeners = useRef([])
|
||||
const mouseEventListeners = useRef([])
|
||||
|
||||
useEffect(() => {
|
||||
if (!canvas) {
|
||||
@ -16,47 +18,56 @@ export function useEvent() {
|
||||
canvas.off(key)
|
||||
}
|
||||
})
|
||||
removeAllKeyboardEventListeners()
|
||||
addEvent(step)
|
||||
}, [step])
|
||||
removeAllMouseEventListeners()
|
||||
removeAllDocumentEventListeners()
|
||||
addDefaultEvent()
|
||||
}, [currentMenu, canvas])
|
||||
|
||||
const addEvent = (step) => {
|
||||
const addDefaultEvent = () => {
|
||||
//default Event 추가
|
||||
canvas?.on('mouse:move', defaultMouseMoveEvent)
|
||||
addKeyboardEventListener('keydown', document, defaultKeyboardEvent)
|
||||
addCanvasMouseEventListener('mouse:move', defaultMouseMoveEvent)
|
||||
addCanvasMouseEventListener('mouse:out', defaultMouseOutEvent)
|
||||
addDocumentEventListener('keydown', document, defaultKeyboardEvent)
|
||||
}
|
||||
|
||||
if (step === 1) {
|
||||
canvas?.on('mouse:down', (e) => {
|
||||
canvas?.add(new fabric.Rect({ width: 100, height: 100, fill: 'red', left: e.pointer.x, top: e.pointer.y }))
|
||||
})
|
||||
addKeyboardEventListener('keydown', document, (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
console.log(1111)
|
||||
}
|
||||
})
|
||||
} else if (step === 2) {
|
||||
canvas?.on('mouse:down', (e) => {
|
||||
canvas?.add(new fabric.Circle({ radius: 50, fill: 'blue', left: e.pointer.x, top: e.pointer.y }))
|
||||
})
|
||||
addKeyboardEventListener('keydown', document, (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
console.log(2222)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
canvas?.on('mouse:down', (e) => {
|
||||
canvas?.add(new fabric.Triangle({ width: 100, height: 100, fill: 'green', left: e.pointer.x, top: e.pointer.y }))
|
||||
})
|
||||
addKeyboardEventListener('keydown', document, (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
console.log(333)
|
||||
}
|
||||
})
|
||||
}
|
||||
const defaultMouseOutEvent = (e) => {
|
||||
removeMouseLine()
|
||||
}
|
||||
|
||||
const defaultMouseMoveEvent = (e) => {
|
||||
console.log('defaultMouseMoveEvent')
|
||||
removeMouseLine()
|
||||
// 가로선
|
||||
const pointer = canvas.getPointer(e.e)
|
||||
const horizontalLine = new fabric.Line([0, pointer.y, 2 * canvas.width, pointer.y], {
|
||||
stroke: 'red',
|
||||
strokeWidth: 1,
|
||||
selectable: false,
|
||||
name: 'mouseLine',
|
||||
})
|
||||
|
||||
// 세로선
|
||||
const verticalLine = new fabric.Line([pointer.x, 0, pointer.x, 2 * canvas.height], {
|
||||
stroke: 'red',
|
||||
strokeWidth: 1,
|
||||
selectable: false,
|
||||
name: 'mouseLine',
|
||||
})
|
||||
|
||||
// 선들을 캔버스에 추가합니다.
|
||||
canvas?.add(horizontalLine, verticalLine)
|
||||
|
||||
// 캔버스를 다시 그립니다.
|
||||
canvas?.renderAll()
|
||||
}
|
||||
|
||||
const removeMouseLine = () => {
|
||||
// 캔버스에서 마우스 선을 찾아 제거합니다.
|
||||
canvas
|
||||
?.getObjects()
|
||||
.filter((obj) => obj.name === 'mouseLine')
|
||||
.forEach((line) => {
|
||||
canvas?.remove(line)
|
||||
})
|
||||
}
|
||||
|
||||
const defaultKeyboardEvent = (e) => {
|
||||
@ -65,21 +76,42 @@ export function useEvent() {
|
||||
}
|
||||
}
|
||||
|
||||
const addCanvasMouseEventListener = (eventType, handler) => {
|
||||
canvas.on(eventType, handler)
|
||||
mouseEventListeners.current.push({ eventType, handler })
|
||||
}
|
||||
|
||||
const removeAllMouseEventListeners = () => {
|
||||
mouseEventListeners.current.forEach(({ eventType, handler }) => {
|
||||
canvas.off(eventType, handler)
|
||||
})
|
||||
mouseEventListeners.current.length = 0 // 배열 초기화
|
||||
}
|
||||
|
||||
/**
|
||||
* document 키보드 이벤트 임의로 직접 등록한 이벤트의 경우 remove가 안되기 때문에 이 함수를 통해서만 등록해야 함.
|
||||
* document 이벤트의 경우 이 함수를 통해서만 등록
|
||||
* @param eventType
|
||||
* @param element
|
||||
* @param handler
|
||||
*/
|
||||
function addKeyboardEventListener(eventType, element, handler) {
|
||||
const addDocumentEventListener = (eventType, element, handler) => {
|
||||
element.addEventListener(eventType, handler)
|
||||
keyboardEventListeners.current.push({ eventType, element, handler })
|
||||
}
|
||||
|
||||
function removeAllKeyboardEventListeners() {
|
||||
/**
|
||||
* document에 등록되는 event 제거
|
||||
*/
|
||||
const removeAllDocumentEventListeners = () => {
|
||||
keyboardEventListeners.current.forEach(({ eventType, element, handler }) => {
|
||||
element.removeEventListener(eventType, handler)
|
||||
})
|
||||
keyboardEventListeners.current.length = 0 // 배열 초기화
|
||||
}
|
||||
|
||||
return {
|
||||
addDocumentEventListener,
|
||||
addCanvasMouseEventListener,
|
||||
removeAllDocumentEventListeners,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { atom } from 'recoil'
|
||||
import { MENU } from '@/common/common'
|
||||
|
||||
export const canvasState = atom({
|
||||
key: 'canvasState',
|
||||
@ -180,7 +181,7 @@ export const objectPlacementModeState = atom({
|
||||
default: { width: 0, height: 0, areaBoundary: false, inputType: 'free', batchType: 'opening' },
|
||||
})
|
||||
|
||||
export const stepState = atom({
|
||||
key: 'step',
|
||||
default: 0,
|
||||
export const currentMenuState = atom({
|
||||
key: 'currentMenu',
|
||||
default: MENU.INITIAL_CANVAS_SETTING,
|
||||
})
|
||||
|
||||
65
src/store/outerLineAtom.js
Normal file
65
src/store/outerLineAtom.js
Normal file
@ -0,0 +1,65 @@
|
||||
import { atom, selector } from 'recoil'
|
||||
|
||||
export const OUTER_LINE_TYPE = {
|
||||
OUTER_LINE: 'outerLine', // 외벽선
|
||||
RIGHT_ANGLE: 'rightAngle', // 직각
|
||||
LEE_GUBAE: 'leeGubae', // 이구배
|
||||
ANGLE: 'angle', // 각도
|
||||
DIAGONAL_LINE: 'diagonalLine', // 대각선
|
||||
}
|
||||
|
||||
/**
|
||||
* 외벽선 작성에서 사용하는 recoilState
|
||||
*/
|
||||
|
||||
export const outerLineLength1State = atom({
|
||||
//길이1
|
||||
key: 'outerLineLength1State',
|
||||
default: 0,
|
||||
})
|
||||
|
||||
export const outerLineLength2State = atom({
|
||||
// 길이2
|
||||
key: 'outerLineLength2State',
|
||||
default: 0,
|
||||
})
|
||||
|
||||
export const outerLineArrow1State = atom({
|
||||
// 방향1
|
||||
key: 'outerLineArrow1State',
|
||||
default: '',
|
||||
})
|
||||
|
||||
export const outerLineArrow2State = atom({
|
||||
// 방향2
|
||||
key: 'outerLineArrow2State',
|
||||
default: '',
|
||||
})
|
||||
|
||||
export const outerLineAngle1State = atom({
|
||||
// 각도1
|
||||
key: 'outerLineAngle1State',
|
||||
default: 0,
|
||||
})
|
||||
|
||||
export const outerLineAngle2State = atom({
|
||||
// 각도2
|
||||
key: 'outerLineAngle2State',
|
||||
default: 0,
|
||||
})
|
||||
|
||||
export const outerLineDiagonalState = atom({
|
||||
// 대각선
|
||||
key: 'outerLineDiagonalState',
|
||||
default: 0,
|
||||
})
|
||||
|
||||
export const outerLineTypeState = atom({
|
||||
key: 'outerLineTypeState',
|
||||
default: OUTER_LINE_TYPE.OUTER_LINE,
|
||||
})
|
||||
|
||||
export const outerLinePointsState = atom({
|
||||
key: 'outerLinePointsState',
|
||||
default: [],
|
||||
})
|
||||
@ -992,7 +992,7 @@ export const splitPolygonWithLines = (polygon) => {
|
||||
/**
|
||||
* 좌표 테스트용
|
||||
*/
|
||||
allLines.forEach((line) => {
|
||||
/*allLines.forEach((line) => {
|
||||
const text = new fabric.Text(`(${line.startPoint.x},${line.startPoint.y})`, {
|
||||
left: line.startPoint.x,
|
||||
top: line.startPoint.y,
|
||||
@ -1021,7 +1021,7 @@ export const splitPolygonWithLines = (polygon) => {
|
||||
|
||||
polygon.canvas.add(text)
|
||||
polygon.canvas.renderAll()
|
||||
})
|
||||
})*/
|
||||
/**
|
||||
* 좌표 테스트용 끝
|
||||
*/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user