From 4aac7c650f6f6ab2d675e032de0e895934076d7a Mon Sep 17 00:00:00 2001 From: minsik Date: Thu, 24 Oct 2024 17:57:40 +0900 Subject: [PATCH] =?UTF-8?q?context=20menu=20=EC=9C=84=EC=B9=98=20=EC=A1=B0?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/color-picker/ColorPickerModal.jsx | 17 +- src/components/common/font/FontSetting.jsx | 11 +- src/components/floor-plan/CanvasFrame.jsx | 7 +- src/components/floor-plan/FloorPlan.jsx | 4 +- .../modal/auxiliary/AuxiliaryMove.jsx | 12 +- .../modal/auxiliary/AuxiliarySize.jsx | 12 +- .../floor-plan/modal/grid/GridCopy.jsx | 11 +- .../floor-plan/modal/grid/GridMove.jsx | 11 +- .../roofAllocation/RoofAllocationSetting.jsx | 6 +- src/hooks/common/useCommonUtils.js | 28 ++- .../roofcover/useRoofAllocationSetting.js | 6 + src/hooks/useContextMenu.js | 194 ++++++++++++++++-- src/hooks/usePopup.js | 6 - src/store/popupAtom.js | 9 + 14 files changed, 277 insertions(+), 57 deletions(-) diff --git a/src/components/common/color-picker/ColorPickerModal.jsx b/src/components/common/color-picker/ColorPickerModal.jsx index 22a3c5c4..add20a7e 100644 --- a/src/components/common/color-picker/ColorPickerModal.jsx +++ b/src/components/common/color-picker/ColorPickerModal.jsx @@ -3,9 +3,12 @@ import ColorPicker from '@/components/common/color-picker/ColorPicker' import { useMessage } from '@/hooks/useMessage' import { useEffect, useState } from 'react' import { usePopup } from '@/hooks/usePopup' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' export default function ColorPickerModal(props) { - const { isShow, setIsShow, pos = { x: 770, y: -815 }, color = '#ff0000', setColor, id } = props + const contextPopupPosition = useRecoilValue(contextPopupPositionState) // 현재 메뉴 + const { isShow, setIsShow, pos = contextPopupPosition, color = '#ff0000', setColor, id } = props const { getMessage } = useMessage() const [originColor, setOriginColor] = useState(color) const { closePopup } = usePopup() @@ -15,14 +18,17 @@ export default function ColorPickerModal(props) { }, [isShow]) return ( - +

{getMessage('modal.color.picker.title')}

) } diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx index 655c7340..bc95d9b3 100644 --- a/src/components/floor-plan/FloorPlan.jsx +++ b/src/components/floor-plan/FloorPlan.jsx @@ -5,14 +5,13 @@ import { useRecoilState, useRecoilValue } from 'recoil' import { useAxios } from '@/hooks/useAxios' import { globalLocaleStore } from '@/store/localeAtom' import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' -import '@/styles/contents.scss' import CanvasMenu from '@/components/floor-plan/CanvasMenu' import CanvasLayout from '@/components/floor-plan/CanvasLayout' +import '@/styles/contents.scss' export default function FloorPlan() { const globalLocaleState = useRecoilValue(globalLocaleStore) const { get } = useAxios(globalLocaleState) - const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState) const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 @@ -23,7 +22,6 @@ export default function FloorPlan() { menuNumber, setMenuNumber, } - useEffect(() => { console.log('FloorPlan useEffect 실행') fetchSettings() diff --git a/src/components/floor-plan/modal/auxiliary/AuxiliaryMove.jsx b/src/components/floor-plan/modal/auxiliary/AuxiliaryMove.jsx index 28674c07..9b4beb8f 100644 --- a/src/components/floor-plan/modal/auxiliary/AuxiliaryMove.jsx +++ b/src/components/floor-plan/modal/auxiliary/AuxiliaryMove.jsx @@ -1,14 +1,20 @@ import { useMessage } from '@/hooks/useMessage' import WithDraggable from '@/components/common/draggable/WithDraggable' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' +import { usePopup } from '@/hooks/usePopup' -export default function AuxiliaryMove({ setCurrentContextMenu }) { +export default function AuxiliaryMove(props) { + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition } = props const { getMessage } = useMessage() + const { closePopup } = usePopup() return ( - +

補助線の移動

-
diff --git a/src/components/floor-plan/modal/auxiliary/AuxiliarySize.jsx b/src/components/floor-plan/modal/auxiliary/AuxiliarySize.jsx index c562e8dd..49cd2570 100644 --- a/src/components/floor-plan/modal/auxiliary/AuxiliarySize.jsx +++ b/src/components/floor-plan/modal/auxiliary/AuxiliarySize.jsx @@ -1,14 +1,20 @@ import { useMessage } from '@/hooks/useMessage' import WithDraggable from '@/components/common/draggable/WithDraggable' +import { usePopup } from '@/hooks/usePopup' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' -export default function AuxiliarySize({ setCurrentContextMenu }) { +export default function AuxiliarySize(props) { + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition } = props const { getMessage } = useMessage() + const { closePopup } = usePopup() return ( - +

補助線サイズ変更

-
diff --git a/src/components/floor-plan/modal/grid/GridCopy.jsx b/src/components/floor-plan/modal/grid/GridCopy.jsx index a6709d09..0f2bfc22 100644 --- a/src/components/floor-plan/modal/grid/GridCopy.jsx +++ b/src/components/floor-plan/modal/grid/GridCopy.jsx @@ -1,16 +1,21 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' import { useMessage } from '@/hooks/useMessage' +import { usePopup } from '@/hooks/usePopup' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' export default function GridCopy(props) { - const { setShowGridMoveModal, setShowGridCopyModal } = props + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition } = props const { getMessage } = useMessage() + const { closePopup } = usePopup() return ( - +

{getMessage('modal.grid.copy')}

-
diff --git a/src/components/floor-plan/modal/grid/GridMove.jsx b/src/components/floor-plan/modal/grid/GridMove.jsx index db226872..6d901fe3 100644 --- a/src/components/floor-plan/modal/grid/GridMove.jsx +++ b/src/components/floor-plan/modal/grid/GridMove.jsx @@ -1,16 +1,21 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' import { useMessage } from '@/hooks/useMessage' +import { usePopup } from '@/hooks/usePopup' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' export default function GridMove(props) { - const { setShowGridMoveModal, setShowGridCopyModal } = props + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition } = props const { getMessage } = useMessage() + const { closePopup } = usePopup() return ( - +

{getMessage('modal.grid.move')}

-
diff --git a/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx b/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx index 934f2f9d..c6afa44d 100644 --- a/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx +++ b/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx @@ -3,8 +3,12 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' import QSelectBox from '@/components/common/select/QSelectBox' import { useRoofAllocationSetting } from '@/hooks/roofcover/useRoofAllocationSetting' import { usePopup } from '@/hooks/usePopup' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' -export default function RoofAllocationSetting({ id, pos = { x: 50, y: 230 } }) { +export default function RoofAllocationSetting(props) { + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition } = props const { getMessage } = useMessage() const { closePopup } = usePopup() const { handleSave, onAddRoofMaterial, onDeleteRoofMaterial, values, roofMaterials, selectedRoofMaterial, setSelectedRoofMaterial } = diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js index dd92253d..7cb605bd 100644 --- a/src/hooks/common/useCommonUtils.js +++ b/src/hooks/common/useCommonUtils.js @@ -4,11 +4,15 @@ import { wordDisplaySelector } from '@/store/settingAtom' import { useEvent } from '@/hooks/useEvent' import { checkLineOrientation, getDistance } from '@/util/canvas-util' import { dimensionLineSettingsState } from '@/store/commonUtilsAtom' +import { v4 as uuidv4 } from 'uuid' +import { usePopup } from '@/hooks/usePopup' +import Distance from '@/components/floor-plan/modal/distance/Distance' export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionState }) { const wordDisplay = useRecoilValue(wordDisplaySelector) const { addCanvasMouseEventListener, addDocumentEventListener, initEvent } = useEvent() const dimensionSettings = useRecoilValue(dimensionLineSettingsState) + const { addPopup } = usePopup() useEffect(() => { initEvent() @@ -98,7 +102,8 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS const lineOptions = { stroke: dimensionSettings.color, strokeWidth: dimensionSettings.pixel, - selectable: false, + name: 'dimensionLine', + selectable: true, } // 캔버스에 클릭 이벤트 추가 @@ -273,6 +278,7 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS const pointer = canvas.getPointer(options.e) let point + console.log(options) if (points.length === 0) { // 첫 번째 포인트는 그대로 클릭한 위치에 추가 point = new fabric.Circle({ @@ -285,7 +291,6 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS } else if (points.length === 1) { // 두 번째 포인트는 첫 번째 포인트를 기준으로 수평 또는 수직으로만 배치 const p1 = points[0] - point = new fabric.Circle({ left: pointer.x - 5, // 반지름 반영 top: pointer.y - 5, // 반지름 반영 @@ -313,9 +318,9 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS canvas.add(line2) canvas.add(line3) - const distance1 = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY) - const distance2 = getDistance(p2CenterX, p2CenterY, p3.x, p3.y) - const distance3 = getDistance(p3.x, p3.y, p1CenterX, p1CenterY) + const distance1 = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY) // 대각선 + const distance2 = getDistance(p2CenterX, p2CenterY, p3.x, p3.y) // 수직거리 + const distance3 = getDistance(p3.x, p3.y, p1CenterX, p1CenterY) // 수평거리 // 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성 distanceText = new fabric.Text(`${distance1 * 10}`, { @@ -339,6 +344,19 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS // 거리 계산 후, 다음 측정을 위해 초기화 points = [] + const id = uuidv4() + addPopup( + id, + 1, + , + ) } // 캔버스 다시 그리기 diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index 9ac4c2aa..3f355111 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -86,6 +86,12 @@ export function useRoofAllocationSetting(id) { swalFire({ text: '할당할 지붕이 없습니다.' }) closePopup(id) } + // if (type === 'roofBase') { + // // 지붕면 할당 + // + // } else if ('roof') { + // // 지붕재 변경 + // } }, []) const onAddRoofMaterial = () => { diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index 4451c259..bbd5115b 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -1,18 +1,36 @@ -import { useRecoilValue } from 'recoil' +import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import { currentMenuState, currentObjectState } from '@/store/canvasAtom' import { useEffect, useState } from 'react' import { MENU } from '@/common/common' import AuxiliaryMove from '@/components/floor-plan/modal/auxiliary/AuxiliaryMove' import AuxiliarySize from '@/components/floor-plan/modal/auxiliary/AuxiliarySize' +import { usePopup } from '@/hooks/usePopup' +import { v4 as uuidv4 } from 'uuid' +import GridMove from '@/components/floor-plan/modal/grid/GridMove' +import GridCopy from '@/components/floor-plan/modal/grid/GridCopy' +import ColorPickerModal from '@/components/common/color-picker/ColorPickerModal' +import { gridColorState } from '@/store/gridAtom' +import { contextPopupPositionState } from '@/store/popupAtom' +import AuxiliaryCopy from '@/components/floor-plan/modal/auxiliary/AuxiliaryCopy' +import SizeSetting from '@/components/floor-plan/modal/object/SizeSetting' +import RoofMaterialSetting from '@/components/floor-plan/modal/object/RoofMaterialSetting' +import DormerOffset from '@/components/floor-plan/modal/object/DormerOffset' +import FontSetting from '@/components/common/font/FontSetting' +import DimensionLineSetting from '@/components/floor-plan/modal/dimensionLine/DimensionLineSetting' +import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting' +import LinePropertySetting from '@/components/floor-plan/modal/lineProperty/LinePropertySetting' +import FlowDirectionSetting from '@/components/floor-plan/modal/flowDirection/FlowDirectionSetting' export function useContextMenu({ externalFn }) { - const currentMenu = useRecoilValue(currentMenuState) - const [contextMenu, setContextMenu] = useState([[]]) - const [currentContextMenu, setCurrentContextMenu] = useState(null) + const currentMenu = useRecoilValue(currentMenuState) // 현재 메뉴 + const setContextPopupPosition = useSetRecoilState(contextPopupPositionState) // 현재 메뉴 + const [contextMenu, setContextMenu] = useState([[]]) // 메뉴.object 별 context menu + const [currentContextMenu, setCurrentContextMenu] = useState(null) // 선택한 contextMenu const currentObject = useRecoilValue(currentObjectState) - - const currentMenuSetting = () => { - console.log(currentMenu) + const { addPopup } = usePopup() + const [popupId, setPopupId] = useState(uuidv4()) + const [gridColor, setGridColor] = useRecoilState(gridColorState) + const currentMenuSetting = (position) => { switch (currentMenu) { case MENU.PLAN_DRAWING: setContextMenu([ @@ -20,14 +38,17 @@ export function useContextMenu({ externalFn }) { { id: 'gridMove', name: '그리드 이동', + component: , }, { id: 'gridCopy', name: '그리드 복사', + component: , }, { id: 'gridColorEdit', name: '그리드 색 변경', + component: , }, { id: 'remove', @@ -84,16 +105,17 @@ export function useContextMenu({ externalFn }) { { id: 'sizeEdit', name: '사이즈 변경', - component: , + component: , }, { id: 'auxiliaryMove', name: '보조선 이동(M)', - component: , + component: , }, { id: 'auxiliaryCopy', name: '보조선 복사(C)', + component: , }, { id: 'auxiliaryRemove', @@ -160,19 +182,35 @@ export function useContextMenu({ externalFn }) { break } } - useEffect(() => { - currentMenuSetting() - }, [currentMenu]) + + const handleClick = (e, menu) => { + setContextPopupPosition({ + x: e.clientX, + y: e.clientY, + }) + setCurrentContextMenu(menu) + } useEffect(() => { + currentMenuSetting() + }, [gridColor, currentMenu]) + + useEffect(() => { + if (currentContextMenu?.component) addPopup(popupId, 1, currentContextMenu?.component) + }, [currentContextMenu]) + + useEffect(() => { + console.log('object name', currentObject?.name) if (currentObject?.name) { switch (currentObject.name) { case 'triangleDormer': + case 'pentagonDormer': setContextMenu([ [ { id: 'sizeEdit', name: '사이즈 변경', + component: , }, { id: 'dormerRemove', @@ -189,10 +227,12 @@ export function useContextMenu({ externalFn }) { { id: 'roofMaterialEdit', name: '지붕재 변경', + component: , }, { id: 'dormerOffset', name: '도머 오프셋', + component: , }, ], ]) @@ -203,6 +243,7 @@ export function useContextMenu({ externalFn }) { { id: 'sizeEdit', name: '사이즈 변경', + component: , }, { id: 'roofMaterialRemove', @@ -221,14 +262,17 @@ export function useContextMenu({ externalFn }) { { id: 'roofMaterialEdit', name: '지붕재 변경', + component: , }, { id: 'linePropertyEdit', name: '각 변 속성 변경', + component: , }, { id: 'flowDirectionEdit', name: '흐름 뱡향 변경', + component: , }, ], ]) @@ -259,6 +303,127 @@ export function useContextMenu({ externalFn }) { ], ]) break + case 'lengthText': + setContextMenu([ + [ + { + id: 'lengthTextRemove', + name: '삭제', + }, + { + id: 'lengthTextMove', + name: '이동', + }, + { + id: 'lengthTextAuxiliaryLineEdit', + name: '치수 보조선 변경', + }, + { + id: 'displayEdit', + name: '표시 변경', + }, + ], + ]) + break + case 'commonText': + setContextMenu([ + [ + { + id: 'commonTextRemove', + name: '삭제', + }, + { + id: 'commonTextMove', + name: '이동', + }, + { + id: 'commonTextCopy', + name: '복사', + }, + { + id: 'commonTextFontSetting', + name: '폰트 설정', + component: , + }, + { + id: 'commonTextEdit', + name: '편집', + }, + ], + ]) + break + case 'lineGrid': + setContextMenu([ + [ + { + id: 'gridMove', + name: '그리드 이동', + }, + { + id: 'gridCopy', + name: '그리드 복사', + }, + { + id: 'gridColorEdit', + name: '그리드 색 변경', + }, + { + id: 'remove', + name: '삭제', + }, + { + id: 'removeAll', + name: '전체 삭제', + }, + ], + ]) + break + case 'dimensionLine': + setContextMenu([ + [ + { + id: 'dimensionLineRemove', + name: '삭제', + }, + { + id: 'dimensionLineMove', + name: '이동', + }, + { + id: 'dimensionAuxiliaryLineEdit', + name: '치수 보조선 변경', + }, + { + id: 'dimensionLineDisplayEdit', + name: '표시 변경', + component: , + }, + ], + ]) + break + case 'shadow': + setContextMenu([ + [ + { + id: 'sizeEdit', + name: '사이즈 변경', + component: , + }, + { + id: 'remove', + name: '삭제(D)', + }, + { + id: 'move', + name: '이동(M)', + }, + { + id: 'copy', + name: '복사(C)', + }, + ], + ]) + break default: currentMenuSetting() } @@ -267,13 +432,10 @@ export function useContextMenu({ externalFn }) { } }, [currentObject]) - useEffect(() => { - console.log(currentContextMenu) - }, [currentContextMenu]) - return { contextMenu, currentContextMenu, setCurrentContextMenu, + handleClick, } } diff --git a/src/hooks/usePopup.js b/src/hooks/usePopup.js index b54492b9..37730ec5 100644 --- a/src/hooks/usePopup.js +++ b/src/hooks/usePopup.js @@ -1,20 +1,14 @@ import { useRecoilState } from 'recoil' import { popupState } from '@/store/popupAtom' -import { useEffect } from 'react' export function usePopup() { const [popup, setPopup] = useRecoilState(popupState) - useEffect(() => { - console.log(popup) - }, [popup]) - const addPopup = (id, depth, component) => { setPopup({ children: [...filterDepth(depth), { id: id, depth: depth, component: component }] }) } const closePopup = (id) => { - console.log(id) setPopup({ children: [...filterChildrenPopup(id).filter((child) => child.id !== id)] }) } diff --git a/src/store/popupAtom.js b/src/store/popupAtom.js index 78de8660..498f4eed 100644 --- a/src/store/popupAtom.js +++ b/src/store/popupAtom.js @@ -11,3 +11,12 @@ export const popupState = atom({ }, dangerouslyAllowMutability: true, }) + +export const contextPopupPositionState = atom({ + key: 'contextPopupPositionState', + default: { + x: 50, + y: 180, + }, + dangerouslyAllowMutability: true, +})