From 363214654d6985fa330e1db6bf571ce20be93f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=8B=9D?= <43837214+Minsiki@users.noreply.github.com> Date: Thu, 26 Dec 2024 13:23:57 +0900 Subject: [PATCH 01/15] =?UTF-8?q?=EC=97=B4.=EB=8B=A8=20=EC=9D=B4=EB=8F=99/?= =?UTF-8?q?=EB=B3=B5=EC=82=AC=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/module/PanelEdit.jsx | 18 +- src/hooks/module/useModule.js | 330 ++++++++++++++++++ 2 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 src/hooks/module/useModule.js diff --git a/src/components/floor-plan/modal/module/PanelEdit.jsx b/src/components/floor-plan/modal/module/PanelEdit.jsx index c63dd0cd..0e7fde7f 100644 --- a/src/components/floor-plan/modal/module/PanelEdit.jsx +++ b/src/components/floor-plan/modal/module/PanelEdit.jsx @@ -9,6 +9,8 @@ import { deepCopyArray } from '@/util/common-utils' import { canvasState } from '@/store/canvasAtom' import * as turf from '@turf/turf' import { POLYGON_TYPE } from '@/common/common' +import { useModal } from '@nextui-org/react' +import { useModule } from '@/hooks/module/useModule' export default function PanelEdit(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) @@ -18,6 +20,7 @@ export default function PanelEdit(props) { const [direction, setDirection] = useState('up') const { getMessage } = useMessage() const canvas = useRecoilValue(canvasState) + const { moduleMove, moduleCopy, moduleMultiMove, moduleMultiCopy } = useModule() useEffect(() => { if (canvas) { @@ -28,7 +31,20 @@ export default function PanelEdit(props) { //모듈 이동 적용 const handleApply = () => { - contextModuleMove(length, direction) + // const activeModuleIds = canvas.getActiveObjects().map((obj) => obj.id) + if (type === 'move') { + moduleMove(length, direction) + } else if (type === 'copy') { + moduleCopy(length, direction) + } else if (type === 'columnMove') { + moduleMultiMove('column', length, direction) + } else if (type === 'columnCopy') { + moduleMultiCopy('column', length, direction) + } else if (type === 'rowMove') { + moduleMultiMove('row', length, direction) + } else if (type === 'rowCopy') { + moduleMultiCopy('row', length, direction) + } closePopup(id) } diff --git a/src/hooks/module/useModule.js b/src/hooks/module/useModule.js new file mode 100644 index 00000000..cc6ef05e --- /dev/null +++ b/src/hooks/module/useModule.js @@ -0,0 +1,330 @@ +import { BATCH_TYPE, POLYGON_TYPE } from '@/common/common' +import { canvasState } from '@/store/canvasAtom' +import { isOverlap, polygonToTurfPolygon } from '@/util/canvas-util' +import { useRecoilValue } from 'recoil' +import { v4 as uuidv4 } from 'uuid' +import * as turf from '@turf/turf' +import { useSwal } from '../useSwal' +import { QPolygon } from '@/components/fabric/QPolygon' + +export function useModule() { + const canvas = useRecoilValue(canvasState) + const { swalFire } = useSwal() + + const moduleMove = (length, direction) => { + const checkModuleDisjointSurface = (squarePolygon, turfModuleSetupSurface) => { + return turf.booleanContains(turfModuleSetupSurface, squarePolygon) || turf.booleanWithin(squarePolygon, turfModuleSetupSurface) + } + + const selectedObj = canvas.getActiveObjects() //선택된 객체들을 가져옴 + const selectedIds = selectedObj.map((obj) => obj.id) // selectedObj의 ID 추출 + + canvas.discardActiveObject() //선택해제 + + const isSetupModules = canvas.getObjects().filter((obj) => obj.name === 'module' && !selectedIds.includes(obj.id)) // selectedObj에 없는 객체만 필터링 + const selectedModules = canvas.getObjects().filter((obj) => selectedIds.includes(obj.id) && obj.name === 'module') //선택했던 객체들만 가져옴 + const setupSurface = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === selectedModules[0].surfaceId)[0] + const isOverlapArray = [] + const isInSurfaceArray = [] + + if (selectedModules) { + canvas.remove(...selectedModules) + selectedModules.forEach((module) => { + module.set({ + originCoords: { + left: module.left, + top: module.top, + }, + }) + + if (direction === 'up') { + module.set({ ...module, top: module.top - Number(length) }) + } else if (direction === 'down') { + module.set({ ...module, top: module.top + Number(length) }) + } else if (direction === 'left') { + module.set({ ...module, left: module.left - Number(length) }) + } else if (direction === 'right') { + module.set({ ...module, left: module.left + Number(length) }) + } + module.setCoords() + canvas.renderAll() + + //다른 모듈과 겹치는지 확인하는 로직 + const isOverlap = isSetupModules.some((isSetupModule) => + turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(isSetupModule, true)), + ) + isOverlapArray.push(isOverlap) + + const turfModuleSetupSurface = polygonToTurfPolygon(setupSurface, true) + const turfModule = polygonToTurfPolygon(module, true) + + //나갔는지 확인하는 로직 + const isInSurface = turf.booleanContains(turfModuleSetupSurface, turfModule) || turf.booleanWithin(turfModule, turfModuleSetupSurface) + isInSurfaceArray.push(isInSurface) + }) + + const isNotOverlap = isOverlapArray.some((isOverlap) => isOverlap) // true면 겹침 + const isNotOutSurface = isInSurfaceArray.every((isOutSurface) => isOutSurface) //false면 밖으로 나감 + + //안겹치고 안나갔으면 이동시킨다 아니면 원래 위치로 돌려놓는다 + if (isNotOverlap || !isNotOutSurface) { + selectedModules.forEach((module) => { + module.set({ ...module, left: module.originCoords.left, top: module.originCoords.top }) + module.setCoords() + }) + } + + canvas.add(...selectedModules) + canvas.renderAll() + } + } + + const moduleCopy = (length, direction) => { + if (canvas.getActiveObjects().length === 0) return + const activeModuleIds = canvas.getActiveObjects().map((obj) => obj.id) + const modules = canvas.getObjects().filter((obj) => activeModuleIds.includes(obj.id)) + const otherModules = canvas.getObjects().filter((obj) => obj.surfaceId === modules[0].surfaceId && obj.name === POLYGON_TYPE.MODULE) + const moduleSetupSurface = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === modules[0].surfaceId)[0] + + canvas.discardActiveObject() //선택해제 + modules.forEach((module) => { + const { top, left } = getPosotion(module, direction, length) + const moduleOptions = { ...module, left, top, id: uuidv4() } + const rect = new QPolygon(module.points, moduleOptions) + canvas.add(rect) + rect.setCoords() + canvas.renderAll() + + // const isOverlapOtherModules = otherModules.some((otherModule) => rect.intersectsWithObject(otherModule)) + const isOverlapOtherModules = otherModules.some( + (otherModule) => + turf.booleanOverlap(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)) || + turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)), + ) + + const isOutsideSurface = + !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(rect, true)) || + !turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(moduleSetupSurface, true)) + + if (isOverlapOtherModules || isOutsideSurface) { + swalFire({ + title: isOverlapOtherModules ? '겹치는 모듈이 있습니다.' : '영역 밖', + icon: 'error', + type: 'confirm', + confirmFn: () => { + canvas.remove(rect) + canvas.renderAll() + }, + }) + } + }) + } + const moduleMultiMove = (type, length, direction) => { + if (canvas.getActiveObjects().length === 0) return + if (canvas.getActiveObjects().length > 1) { + swalFire({ + title: '여러 개의 모듈을 선택할 수 없습니다.', + icon: 'error', + type: 'alert', + }) + canvas.discardActiveObject() + return + } + const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] + const modules = type === 'row' ? getRowModules(activeModule) : getColumnModules(activeModule) + const otherModules = getOtherModules(modules) + const objects = getObjects() + const moduleSetupSurface = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0] + let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] + + modules.forEach((module) => { + const { top, left } = getPosotion(module, direction, length, false) + module.originPos = { + top: module.top, + left: module.left, + } + + module.set({ top, left }) + module.setCoords() + canvas.renderAll() + + if (otherModules.length > 0) { + isOverlapOtherModules.push( + otherModules.some( + (otherModule) => + turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(otherModule, true)) || + turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(otherModule, true)), + ), + ) + } + + if (objects.length > 0) { + isOverlapObjects.push( + objects.some( + (object) => + turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)) || + turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)), + ), + ) + } + + isOutsideSurface.push( + !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(module, true)) || + !turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(moduleSetupSurface, true)), + ) + }) + + if ( + isOverlapOtherModules.some((isOverlap) => isOverlap) || + isOverlapObjects.some((isOverlap) => isOverlap) || + isOutsideSurface.some((isOutside) => isOutside) + ) { + swalFire({ + title: isOverlapOtherModules.some((isOverlap) => isOverlap) ? '겹치는 모듈이 있습니다.' : '영역 밖', + icon: 'error', + type: 'confirm', + confirmFn: () => { + modules.forEach((module) => { + module.set({ top: module.originPos.top, left: module.originPos.left }) + module.setCoords() + }) + canvas.renderAll() + }, + }) + } + } + + const moduleMultiCopy = (type, length, direction) => { + if (canvas.getActiveObjects().length === 0) return + if (canvas.getActiveObjects().length > 1) { + swalFire({ + title: '여러 개의 모듈을 선택할 수 없습니다.', + icon: 'error', + type: 'alert', + }) + canvas.discardActiveObject() + return + } + const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] + const modules = type === 'row' ? getRowModules(activeModule) : getColumnModules(activeModule) + const otherModules = canvas.getObjects().filter((obj) => obj.surfaceId === modules[0].surfaceId && obj.name === POLYGON_TYPE.MODULE) + const objects = getObjects() + const copyRects = [] + const moduleSetupSurface = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === modules[0].surfaceId)[0] + let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] + + modules.forEach((module) => { + const { top, left } = getPosotion(module, direction, length, true) + const moduleOptions = { ...module, left, top, id: uuidv4() } + const rect = new QPolygon(module.points, moduleOptions) + canvas.add(rect) + copyRects.push(rect) + module.setCoords() + + if (otherModules.length > 0) { + isOverlapOtherModules.push( + otherModules.some( + (otherModule) => + turf.booleanOverlap(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)) || + turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)), + ), + ) + } + + if (objects.length > 0) { + isOverlapObjects.push( + objects.some( + (object) => + turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)) || + turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)), + ), + ) + } + + isOutsideSurface.push( + !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(rect, true)) || + !turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(moduleSetupSurface, true)), + ) + }) + + console.log( + '🚀 ~ moduleMultiCopy ~ sOverlapOtherModules, isOverlapObjects, isOutsideSurface:', + isOverlapOtherModules, + isOverlapObjects, + isOutsideSurface, + ) + if ( + isOverlapOtherModules.some((isOverlap) => isOverlap) || + isOverlapObjects.some((isOverlap) => isOverlap) || + isOutsideSurface.some((isOutside) => isOutside) + ) { + swalFire({ + title: isOverlapOtherModules.some((isOverlap) => isOverlap) ? '겹치는 모듈이 있습니다.' : '영역 밖', + icon: 'error', + type: 'confirm', + confirmFn: () => { + canvas.remove(...copyRects) + canvas.renderAll() + }, + }) + } else { + canvas.renderAll() + } + } + + const getRowModules = (target) => { + return canvas.getObjects().filter((obj) => target.surfaceId === obj.surfaceId && obj.name === POLYGON_TYPE.MODULE && obj.top === target.top) + } + + const getColumnModules = (target) => { + return canvas.getObjects().filter((obj) => target.surfaceId === obj.surfaceId && obj.name === POLYGON_TYPE.MODULE && obj.left === target.left) + } + + const getPosotion = (target, direction, length, hasMargin = false) => { + let top = target.top + let left = target.left + + if (direction === 'up') { + top = Number(target.top) - Number(length) + top = hasMargin ? top - Number(target.height) : top + } else if (direction === 'down') { + top = Number(target.top) + Number(target.height) + Number(length) + top = hasMargin ? top + Number(target.height) : top + } else if (direction === 'left') { + left = Number(target.left) - Number(length) + left = hasMargin ? left - Number(target.width) : left + } else if (direction === 'right') { + left = Number(target.left) + Number(length) + left = hasMargin ? left + Number(target.width) : left + } + return { top, left } + } + + const getOtherModules = (modules) => { + const moduleIds = modules.map((module) => module.id) + return canvas + .getObjects() + .filter((obj) => obj.surfaceId === modules[0].surfaceId && obj.name === POLYGON_TYPE.MODULE && !moduleIds.includes(obj.id)) + } + + const getObjects = () => { + return canvas + ?.getObjects() + .filter((obj) => [BATCH_TYPE.OPENING, BATCH_TYPE.TRIANGLE_DORMER, BATCH_TYPE.PENTAGON_DORMER, BATCH_TYPE.SHADOW].includes(obj.name)) + } + + return { + moduleMove, + moduleMultiMove, + moduleCopy, + moduleMultiCopy, + } +} From f56e5ca4b0e2543d604a135bd2afb2dbb0743d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=8B=9D?= <43837214+Minsiki@users.noreply.github.com> Date: Thu, 26 Dec 2024 18:07:55 +0900 Subject: [PATCH 02/15] =?UTF-8?q?=EC=97=B4.=EB=8B=A8=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/module/PanelEdit.jsx | 23 +- .../modal/module/column/ColumnRemove.jsx | 27 +- .../floor-plan/modal/module/row/RowRemove.jsx | 29 +- src/hooks/module/useModule.js | 279 +++++++++++++++++- src/hooks/useContextMenu.js | 14 +- 5 files changed, 326 insertions(+), 46 deletions(-) diff --git a/src/components/floor-plan/modal/module/PanelEdit.jsx b/src/components/floor-plan/modal/module/PanelEdit.jsx index 0e7fde7f..a3a89dcf 100644 --- a/src/components/floor-plan/modal/module/PanelEdit.jsx +++ b/src/components/floor-plan/modal/module/PanelEdit.jsx @@ -12,9 +12,18 @@ import { POLYGON_TYPE } from '@/common/common' import { useModal } from '@nextui-org/react' import { useModule } from '@/hooks/module/useModule' +export const PANEL_EDIT_TYPE = { + MOVE: 'move', + COPY: 'copy', + COLUMN_MOVE: 'columnMove', + COLUMN_COPY: 'columnCopy', + ROW_MOVE: 'rowMove', + ROW_COPY: 'rowCopy', +} + export default function PanelEdit(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) - const { id, pos = contextPopupPosition, type = 'move', apply } = props + const { id, pos = contextPopupPosition, type = PANEL_EDIT_TYPE.MOVE, apply } = props const { closePopup } = usePopup() const [length, setLength] = useState(0) const [direction, setDirection] = useState('up') @@ -32,17 +41,17 @@ export default function PanelEdit(props) { //모듈 이동 적용 const handleApply = () => { // const activeModuleIds = canvas.getActiveObjects().map((obj) => obj.id) - if (type === 'move') { + if (type === PANEL_EDIT_TYPE.MOVE) { moduleMove(length, direction) - } else if (type === 'copy') { + } else if (type === PANEL_EDIT_TYPE.COPY) { moduleCopy(length, direction) - } else if (type === 'columnMove') { + } else if (type === PANEL_EDIT_TYPE.COLUMN_MOVE) { moduleMultiMove('column', length, direction) - } else if (type === 'columnCopy') { + } else if (type === PANEL_EDIT_TYPE.COLUMN_COPY) { moduleMultiCopy('column', length, direction) - } else if (type === 'rowMove') { + } else if (type === PANEL_EDIT_TYPE.ROW_MOVE) { moduleMultiMove('row', length, direction) - } else if (type === 'rowCopy') { + } else if (type === PANEL_EDIT_TYPE.ROW_COPY) { moduleMultiCopy('row', length, direction) } closePopup(id) diff --git a/src/components/floor-plan/modal/module/column/ColumnRemove.jsx b/src/components/floor-plan/modal/module/column/ColumnRemove.jsx index 24219d78..a18d7982 100644 --- a/src/components/floor-plan/modal/module/column/ColumnRemove.jsx +++ b/src/components/floor-plan/modal/module/column/ColumnRemove.jsx @@ -5,21 +5,24 @@ import { usePopup } from '@/hooks/usePopup' import { useMessage } from '@/hooks/useMessage' import { useState } from 'react' import Image from 'next/image' +import { MODULE_REMOVE_TYPE, useModule } from '@/hooks/module/useModule' export default function ColumnRemove(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) const { id, pos = contextPopupPosition, apply } = props const { closePopup } = usePopup() - const [selectedType, setSelectedType] = useState(1) + const [selectedType, setSelectedType] = useState(MODULE_REMOVE_TYPE.LEFT) const { getMessage } = useMessage() + const { moduleColumnRemove } = useModule() const types = [ - { name: getMessage('modal.panel.column.remove.type.left'), value: 1 }, - { name: getMessage('modal.panel.column.remove.type.right'), value: 2 }, - { name: getMessage('modal.panel.column.remove.type.side'), value: 3 }, - { name: getMessage('modal.panel.column.remove.type.none'), value: 4 }, + { name: getMessage('modal.panel.column.remove.type.left'), value: MODULE_REMOVE_TYPE.LEFT }, + { name: getMessage('modal.panel.column.remove.type.right'), value: MODULE_REMOVE_TYPE.RIGHT }, + { name: getMessage('modal.panel.column.remove.type.side'), value: MODULE_REMOVE_TYPE.HORIZONTAL_SIDE }, + { name: getMessage('modal.panel.column.remove.type.none'), value: MODULE_REMOVE_TYPE.NONE }, ] const handleApply = () => { - if (apply) apply() + // if (apply) apply() + moduleColumnRemove(selectedType) closePopup(id) } @@ -39,12 +42,12 @@ export default function ColumnRemove(props) {
{types.map((type, index) => { return ( -
+
setSelectedType(Number(e.target.value))} + onClick={(e) => setSelectedType(e.target.value)} value={type.value} checked={selectedType === type.value} /> @@ -54,7 +57,7 @@ export default function ColumnRemove(props) { })}
- {selectedType === 1 && ( + {selectedType === MODULE_REMOVE_TYPE.LEFT && ( react )} - {selectedType === 2 && ( + {selectedType === MODULE_REMOVE_TYPE.RIGHT && ( react )} - {selectedType === 3 && ( + {selectedType === MODULE_REMOVE_TYPE.HORIZONTAL_SIDE && ( react )} - {selectedType === 4 && ( + {selectedType === MODULE_REMOVE_TYPE.NONE && ( react { - if (apply) apply() + // if (apply) apply() + moduleRowRemove(selectedType) closePopup(id) } @@ -39,22 +42,22 @@ export default function RowRemove(props) {
{types.map((type, index) => { return ( -
+
setSelectedType(Number(e.target.value))} + onClick={(e) => setSelectedType(e.target.value)} value={type.value} checked={selectedType === type.value} /> - +
) })}
- {selectedType === 1 && ( + {selectedType === MODULE_REMOVE_TYPE.TOP && ( react )} - {selectedType === 2 && ( + {selectedType === MODULE_REMOVE_TYPE.BOTTOM && ( react )} - {selectedType === 3 && ( + {selectedType === MODULE_REMOVE_TYPE.VERTICAL_SIDE && ( react )} - {selectedType === 4 && ( + {selectedType === MODULE_REMOVE_TYPE.NONE && ( react { - const { top, left } = getPosotion(module, direction, length) + const { top, left } = getPosotion(module, direction, length, true) const moduleOptions = { ...module, left, top, id: uuidv4() } const rect = new QPolygon(module.points, moduleOptions) canvas.add(rect) @@ -255,12 +265,6 @@ export function useModule() { ) }) - console.log( - '🚀 ~ moduleMultiCopy ~ sOverlapOtherModules, isOverlapObjects, isOutsideSurface:', - isOverlapOtherModules, - isOverlapObjects, - isOutsideSurface, - ) if ( isOverlapOtherModules.some((isOverlap) => isOverlap) || isOverlapObjects.some((isOverlap) => isOverlap) || @@ -280,6 +284,265 @@ export function useModule() { } } + const getIsOverlapOtherModules = (module, otherModules) => { + return otherModules.some( + (otherModule) => + turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(otherModule, true)) || + turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(otherModule, true)), + ) + } + + const getIsOverlapObjects = (module, objects) => { + return objects.some( + (object) => + turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)) || + turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)), + ) + } + + const getIsOutsideSurface = (module, moduleSetupSurface) => { + return ( + !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(module, true)) || + !turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(moduleSetupSurface, true)) + ) + } + + const moduleColumnRemove = (type) => { + const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] + const columnModules = getColumnModules(activeModule) + const otherModules = getOtherModules(columnModules) + const objects = getObjects() + console.log('🚀 ~ moduleColumnRemove ~ objects:', objects) + let targetModules = [] + const rightModules = otherModules.filter((module) => activeModule.left < module.left).sort((a, b) => a.left - b.left) + const leftModules = otherModules.filter((module) => activeModule.left > module.left).sort((a, b) => b.left - a.left) + let width = -1 + const moduleSetupSurface = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0] + let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] + console.log( + '🚀 ~ moduleColumnRemove ~ isOverlapOtherModules, isOverlapObjects, isOutsideSurface:', + isOverlapOtherModules, + isOverlapObjects, + isOutsideSurface, + ) + + canvas.discardActiveObject() + canvas.remove(...columnModules) + canvas.renderAll() + + if (type === MODULE_REMOVE_TYPE.LEFT) { + console.log('🚀 ~ moduleColumnRemove ~ rightModules:', rightModules) + rightModules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + } + if (width === -1) width = module.left - activeModule.left + module.set({ left: module.left - width }) + module.setCoords() + canvas.renderAll() + isOverlapOtherModules.push(getIsOverlapOtherModules(module, leftModules)) + isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) + }) + targetModules = rightModules + } else if (type === MODULE_REMOVE_TYPE.RIGHT) { + leftModules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + } + if (width === -1) width = activeModule.left - module.left + module.set({ left: module.left + width }) + module.setCoords() + canvas.renderAll() + isOverlapOtherModules.push(getIsOverlapOtherModules(module, rightModules)) + isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) + }) + targetModules = leftModules + } else if (type === MODULE_REMOVE_TYPE.HORIZONTAL_SIDE) { + const sideModules = [...leftModules, ...rightModules] + leftModules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + } + if (width === -1) width = activeModule.left - module.left + module.set({ left: module.left + width / 2 }) + module.setCoords() + canvas.renderAll() + }) + + rightModules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + } + if (width === -1) width = module.left - activeModule.left + module.set({ left: module.left - width / 2 }) + module.setCoords() + canvas.renderAll() + }) + canvas.renderAll() + sideModules.forEach((module) => { + isOverlapOtherModules.push( + getIsOverlapOtherModules( + module, + sideModules.filter((m) => m.id !== module.id), + ), + ) + isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) + }) + + targetModules = sideModules + } + console.log('🚀 ~ sideModules.forEach ~ objects:', objects) + console.log( + '🚀 ~ moduleColumnRemove ~ isOverlapOtherModules, isOverlapObjects, isOutsideSurface:', + isOverlapOtherModules, + isOverlapObjects, + isOutsideSurface, + ) + if ( + (isOverlapOtherModules.some((isOverlap) => isOverlap) || + isOverlapObjects.some((isOverlap) => isOverlap) || + isOutsideSurface.some((isOutside) => isOutside)) && + type !== MODULE_REMOVE_TYPE.NONE + ) { + swalFire({ + title: + isOverlapOtherModules.some((isOverlap) => isOverlap) || isOverlapObjects.some((isOverlap) => isOverlap) + ? '겹치는 모듈이 있습니다.' + : '영역 밖', + icon: 'error', + type: 'confirm', + confirmFn: () => { + canvas.add(...columnModules) + targetModules.forEach((module) => { + module.set({ top: module.originPos.top, left: module.originPos.left }) + module.setCoords() + }) + canvas.renderAll() + }, + }) + } + } + + const moduleRowRemove = (type) => { + const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] + const rowModules = getRowModules(activeModule) + const otherModules = getOtherModules(rowModules) + const objects = getObjects() + let targetModules = [] + const topModules = otherModules.filter((module) => activeModule.top > module.top).sort((a, b) => b.top - a.top) + const bottomModules = otherModules.filter((module) => activeModule.top < module.top).sort((a, b) => a.top - b.top) + let height = -1 + const moduleSetupSurface = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0] + let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] + + canvas.discardActiveObject() + canvas.remove(...rowModules) + canvas.renderAll() + + if (type === MODULE_REMOVE_TYPE.TOP) { + bottomModules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + } + if (height === -1) height = module.top - activeModule.top + module.set({ top: module.top - height }) + module.setCoords() + canvas.renderAll() + isOverlapOtherModules.push(getIsOverlapOtherModules(module, topModules)) + isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) + }) + targetModules = bottomModules + } else if (type === MODULE_REMOVE_TYPE.BOTTOM) { + topModules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + } + if (height === -1) height = activeModule.top - module.top + module.set({ top: module.top + height }) + module.setCoords() + canvas.renderAll() + isOverlapOtherModules.push(getIsOverlapOtherModules(module, bottomModules)) + isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) + }) + targetModules = topModules + } else if (type === MODULE_REMOVE_TYPE.VERTICAL_SIDE) { + topModules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + } + if (height === -1) height = activeModule.top - module.top + module.set({ top: module.top + height / 2 }) + module.setCoords() + canvas.renderAll() + }) + + bottomModules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + } + if (height === -1) height = module.top - activeModule.top + module.set({ top: module.top - height / 2 }) + module.setCoords() + canvas.renderAll() + }) + + const sideModules = [...topModules, ...bottomModules] + canvas.renderAll() + sideModules.forEach((module) => { + isOverlapOtherModules.push( + getIsOverlapOtherModules( + module, + sideModules.filter((m) => m.id !== module.id), + ), + ) + isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) + }) + targetModules = sideModules + } + + if ( + (isOverlapOtherModules.some((isOverlap) => isOverlap) || + isOverlapObjects.some((isOverlap) => isOverlap) || + isOutsideSurface.some((isOutside) => isOutside)) && + type !== MODULE_REMOVE_TYPE.NONE + ) { + swalFire({ + title: + isOverlapOtherModules.some((isOverlap) => isOverlap) || isOverlapObjects.some((isOverlap) => isOverlap) + ? '겹치는 모듈이 있습니다.' + : '영역 밖', + icon: 'error', + type: 'confirm', + confirmFn: () => { + canvas.add(...rowModules) + targetModules.forEach((module) => { + module.set({ top: module.originPos.top, left: module.originPos.left }) + module.setCoords() + }) + canvas.renderAll() + }, + }) + } + } + const getRowModules = (target) => { return canvas.getObjects().filter((obj) => target.surfaceId === obj.surfaceId && obj.name === POLYGON_TYPE.MODULE && obj.top === target.top) } @@ -326,5 +589,7 @@ export function useModule() { moduleMultiMove, moduleCopy, moduleMultiCopy, + moduleColumnRemove, + moduleRowRemove, } } diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index 38564f7b..ad662534 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -23,7 +23,7 @@ import { useCommonUtils } from './common/useCommonUtils' import { useMessage } from '@/hooks/useMessage' import { useCanvasEvent } from '@/hooks/useCanvasEvent' import { contextMenuListState, contextMenuState } from '@/store/contextMenu' -import PanelEdit from '@/components/floor-plan/modal/module/PanelEdit' +import PanelEdit, { PANEL_EDIT_TYPE } from '@/components/floor-plan/modal/module/PanelEdit' import DimensionLineSetting from '@/components/floor-plan/modal/dimensionLine/DimensionLineSetting' import ColumnRemove from '@/components/floor-plan/modal/module/column/ColumnRemove' import ColumnInsert from '@/components/floor-plan/modal/module/column/ColumnInsert' @@ -609,24 +609,24 @@ export function useContextMenu() { { id: 'move', name: getMessage('contextmenu.move'), - component: , + component: , }, { id: 'copy', name: getMessage('contextmenu.copy'), - component: , + component: , }, ], [ { id: 'columnMove', name: getMessage('contextmenu.column.move'), - component: , + component: , }, { id: 'columnCopy', name: getMessage('contextmenu.column.copy'), - component: , + component: , }, { id: 'columnRemove', @@ -643,12 +643,12 @@ export function useContextMenu() { { id: 'rowMove', name: getMessage('contextmenu.row.move'), - component: , + component: , }, { id: 'rowCopy', name: getMessage('contextmenu.row.copy'), - component: , + component: , }, { id: 'rowRemove', From 7895538c1fd11334b0e3faf4ab96bd10e5e3dacc Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Fri, 27 Dec 2024 11:04:57 +0900 Subject: [PATCH 03/15] =?UTF-8?q?=F0=9F=93=8C=20Add=20MainLayoutDiagram?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MainLayout.codediagram | 1 + 1 file changed, 1 insertion(+) create mode 100644 MainLayout.codediagram diff --git a/MainLayout.codediagram b/MainLayout.codediagram new file mode 100644 index 00000000..ec747fa4 --- /dev/null +++ b/MainLayout.codediagram @@ -0,0 +1 @@ +null \ No newline at end of file From 57c9cc906b3eb1af08ccdf1188c1ca3ed08b96da Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Fri, 27 Dec 2024 11:13:51 +0900 Subject: [PATCH 04/15] =?UTF-8?q?=F0=9F=93=8Cfix:=20MainLayoutDiagram=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MainLayout.codediagram | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MainLayout.codediagram b/MainLayout.codediagram index ec747fa4..baf0aca3 100644 --- a/MainLayout.codediagram +++ b/MainLayout.codediagram @@ -1 +1 @@ -null \ No newline at end of file +{"id":-1,"name":"FROM_FILE","userId":-1,"createdAt":"","updatedAt":"","content":{"items":[{"uid":"jsIqfLoyaa","position":{"x":160,"y":360},"sizes":{"width":720,"height":522},"autoheight":true,"blockContent":{"content":[{"type":"filePathNode","attrs":{"pathToFile":"src/app/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"layout.js"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"\n \n \n {headerPathname === '/login' || headerPathname === '/join' ? (\n {children}\n ) : (\n \n
\n
\n
\n \n {children}\n
\n
\n
\n
\n )}\n \n \n \n \n
"}]}]},"nodeType":"block"},{"uid":"yOseUHcOzU","position":{"x":1020,"y":480},"sizes":{"width":557.5,"height":189.5},"autoheight":true,"blockContent":{"content":[{"type":"filePathNode","attrs":{"pathToFile":"src/app/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"RecoilWrapper.js"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function RecoilRootWrapper({ children }) {\n return {children}\n}"}]}]},"nodeType":"block"},{"uid":"ohc4COfFLi","position":{"x":1680,"y":370},"sizes":{"width":840.5,"height":312},"autoheight":true,"blockContent":{"content":[{"type":"filePathNode","attrs":{"pathToFile":"src/app/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"QcastProvider.js"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"<>\n {isGlobalLoading && (\n
\n \n
\n )}\n \n }>{children}\n \n"}]}]},"nodeType":"block"},{"uid":"LQIlkk7G7c","position":{"x":2700,"y":160},"sizes":{"width":400,"height":109},"autoheight":true,"blockContent":{"content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/header/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"Header.jsx"}]},{"type":"paragraph","content":[{"type":"text","text":" "}]}]},"nodeType":"block"},{"uid":"h-RKXEf7EQ","position":{"x":2710,"y":360},"sizes":{"width":792.5,"height":207},"autoheight":true,"blockContent":{"content":[{"type":"filePathNode","attrs":{"pathToFile":"src/app/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"SessionProvider.js"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function SessionProvider({ useSession, children }) {\n const [session, setSession] = useState(useSession)\n return {children}\n}"}]}]},"nodeType":"block"},{"uid":"eMjqDGJ7H-","position":{"x":2710,"y":660},"sizes":{"width":400,"height":109},"autoheight":true,"blockContent":{"content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/footer/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"Footer.jsx"}]},{"type":"paragraph","content":[{"type":"text","text":" "}]}]},"nodeType":"block"},{"uid":"HjtO7B4Big","position":{"x":1110,"y":730},"sizes":{"width":400,"height":312},"autoheight":true,"blockContent":{"content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/common/popupManager/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"PopupManager.jsx"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function PopupManager() {\n const popup = useRecoilValue(popupState)\n\n return [\n ...popup?.config.map((child) => {child.component}),\n ...popup?.other.map((child) => {child.component}),\n ]\n}"}]}]},"nodeType":"block"},{"uid":"VyJRuoccdZ","position":{"x":3620,"y":400},"sizes":{"width":190,"height":95},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"type":"text","marks":[{"type":"bold"},{"type":"italic"}],"text":"{children}"}]}]},"nodeType":"block"},{"uid":"BO78hOqExy","position":{"x":1750,"y":140},"sizes":{"width":400,"height":109},"autoheight":true,"blockContent":{"content":[{"type":"filePathNode","attrs":{"pathToFile":"node_modules/next/dist/client/components/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"error-boundary.d.ts"}]},{"type":"paragraph","content":[{"type":"text","text":" "}]}]},"nodeType":"block"}],"configs":{"centerX":-818,"centerY":-32,"zoomLevel":1},"arrowData":{"arrowsMap":{},"pointsMap":{},"edgesMap":{"edge-jsIqfLoyaa-jsIqfLoyaa-right-yOseUHcOzU-yOseUHcOzU-left":{"uid":"edge-jsIqfLoyaa-jsIqfLoyaa-right-yOseUHcOzU-yOseUHcOzU-left","fromNodeId":"jsIqfLoyaa","fromHandleId":"jsIqfLoyaa-right","toNodeId":"yOseUHcOzU","toHandleId":"yOseUHcOzU-left","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-yOseUHcOzU-yOseUHcOzU-right-ohc4COfFLi-ohc4COfFLi-left":{"uid":"edge-yOseUHcOzU-yOseUHcOzU-right-ohc4COfFLi-ohc4COfFLi-left","fromNodeId":"yOseUHcOzU","fromHandleId":"yOseUHcOzU-right","toNodeId":"ohc4COfFLi","toHandleId":"ohc4COfFLi-left","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-ohc4COfFLi-ohc4COfFLi-right-LQIlkk7G7c-LQIlkk7G7c-left":{"uid":"edge-ohc4COfFLi-ohc4COfFLi-right-LQIlkk7G7c-LQIlkk7G7c-left","fromNodeId":"ohc4COfFLi","fromHandleId":"ohc4COfFLi-right","toNodeId":"LQIlkk7G7c","toHandleId":"LQIlkk7G7c-left","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-ohc4COfFLi-ohc4COfFLi-right-h-RKXEf7EQ-h-RKXEf7EQ-left":{"uid":"edge-ohc4COfFLi-ohc4COfFLi-right-h-RKXEf7EQ-h-RKXEf7EQ-left","fromNodeId":"ohc4COfFLi","fromHandleId":"ohc4COfFLi-right","toNodeId":"h-RKXEf7EQ","toHandleId":"h-RKXEf7EQ-left","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-ohc4COfFLi-ohc4COfFLi-right-eMjqDGJ7H--eMjqDGJ7H--left":{"uid":"edge-ohc4COfFLi-ohc4COfFLi-right-eMjqDGJ7H--eMjqDGJ7H--left","fromNodeId":"ohc4COfFLi","fromHandleId":"ohc4COfFLi-right","toNodeId":"eMjqDGJ7H-","toHandleId":"eMjqDGJ7H--left","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-yOseUHcOzU-yOseUHcOzU-bottom-HjtO7B4Big-HjtO7B4Big-top":{"uid":"edge-yOseUHcOzU-yOseUHcOzU-bottom-HjtO7B4Big-HjtO7B4Big-top","fromNodeId":"yOseUHcOzU","fromHandleId":"yOseUHcOzU-bottom","toNodeId":"HjtO7B4Big","toHandleId":"HjtO7B4Big-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-h-RKXEf7EQ-h-RKXEf7EQ-right-VyJRuoccdZ-VyJRuoccdZ-left":{"uid":"edge-h-RKXEf7EQ-h-RKXEf7EQ-right-VyJRuoccdZ-VyJRuoccdZ-left","fromNodeId":"h-RKXEf7EQ","fromHandleId":"h-RKXEf7EQ-right","toNodeId":"VyJRuoccdZ","toHandleId":"VyJRuoccdZ-left","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-BO78hOqExy-BO78hOqExy-bottom-ohc4COfFLi-ohc4COfFLi-top":{"uid":"edge-BO78hOqExy-BO78hOqExy-bottom-ohc4COfFLi-ohc4COfFLi-top","fromNodeId":"BO78hOqExy","fromHandleId":"BO78hOqExy-bottom","toNodeId":"ohc4COfFLi","toHandleId":"ohc4COfFLi-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}}}}}} \ No newline at end of file From ddbfca3f16fcba6987329bb85656ccb8bb95a547 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Fri, 27 Dec 2024 14:46:32 +0900 Subject: [PATCH 05/15] =?UTF-8?q?=F0=9F=93=8C=20fix:=20Add=20sample=20redu?= =?UTF-8?q?cer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Playground.jsx | 4 + src/components/sample/SampleReducer.jsx | 115 ++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 src/components/sample/SampleReducer.jsx diff --git a/src/components/Playground.jsx b/src/components/Playground.jsx index e2901061..fcc5468d 100644 --- a/src/components/Playground.jsx +++ b/src/components/Playground.jsx @@ -25,6 +25,7 @@ import QPagination from './common/pagination/QPagination' import { trestleRequestModels, constructionRequestModels, trestleDetailRequestModels } from '@/models/apiModels' import QSelectBox from './common/select/QSelectBox' +import SampleReducer from './sample/SampleReducer' export default function Playground() { const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState) @@ -504,6 +505,9 @@ export default function Playground() {
+
+ +
) diff --git a/src/components/sample/SampleReducer.jsx b/src/components/sample/SampleReducer.jsx new file mode 100644 index 00000000..26150fea --- /dev/null +++ b/src/components/sample/SampleReducer.jsx @@ -0,0 +1,115 @@ +import { Card, CardBody, Input, Tab, Tabs } from '@nextui-org/react' +import { useEffect, useReducer } from 'react' + +const reducer = (prevState, nextState) => { + return { ...prevState, ...nextState } +} + +const defaultData = { + commonData: 'common', + tabs: [ + { + id: 1, + name: 'tab1', + range: 10, + maker: 'maker1', + law: 'law1', + basis: 'basis1', + }, + { + id: 2, + name: 'tab2', + range: 20, + maker: 'maker2', + law: 'law2', + basis: 'basis2', + }, + { + id: 3, + name: 'tab3', + range: 30, + maker: 'maker3', + law: 'law3', + basis: 'basis3', + }, + { + id: 4, + name: 'tab4', + range: 40, + maker: 'maker4', + law: 'law4', + basis: 'basis4', + }, + ], +} + +export default function SampleReducer() { + const [sampleState, setSampleState] = useReducer(reducer, defaultData) + + const handleChangeTabsData = (newTab) => { + const newTabs = sampleState.tabs.map((t) => { + if (t.id === newTab.id) { + return newTab + } else { + return t + } + }) + setSampleState({ ...sampleState, tabs: newTabs }) + } + + useEffect(() => { + console.log('🚀 ~ SampleReducer ~ sampleState:', sampleState) + }, [sampleState]) + + return ( + <> +
공통: {sampleState.commonData}
+
+ + {sampleState.tabs.map((s) => ( + + + +
+ { + handleChangeTabsData({ ...s, range: e.target.value }) + }} + /> + { + handleChangeTabsData({ ...s, maker: e.target.value }) + }} + /> + { + handleChangeTabsData({ ...s, law: e.target.value }) + }} + /> + { + handleChangeTabsData({ ...s, basis: e.target.value }) + }} + /> +
+
+
+
+ ))} +
+
+ + ) +} From f08e1fd4ff58f343d73696ca7952bbd89eac90b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=8B=9D?= <43837214+Minsiki@users.noreply.github.com> Date: Fri, 27 Dec 2024 16:34:42 +0900 Subject: [PATCH 06/15] =?UTF-8?q?=EB=AA=A8=EB=93=88=20=EC=97=B4.=EB=8B=A8?= =?UTF-8?q?=20=EC=82=AD=EC=A0=9C=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/module/useModule.js | 186 ++++++++++++---------- src/hooks/module/useModuleBasicSetting.js | 125 ++++++++------- 2 files changed, 163 insertions(+), 148 deletions(-) diff --git a/src/hooks/module/useModule.js b/src/hooks/module/useModule.js index 4e2651fe..5eb95f6a 100644 --- a/src/hooks/module/useModule.js +++ b/src/hooks/module/useModule.js @@ -1,11 +1,12 @@ import { BATCH_TYPE, POLYGON_TYPE } from '@/common/common' import { canvasState } from '@/store/canvasAtom' -import { isOverlap, polygonToTurfPolygon } from '@/util/canvas-util' +import { isOverlap, polygonToTurfPolygon, rectToPolygon } from '@/util/canvas-util' import { useRecoilValue } from 'recoil' import { v4 as uuidv4 } from 'uuid' import * as turf from '@turf/turf' import { useSwal } from '../useSwal' import { QPolygon } from '@/components/fabric/QPolygon' +import { useModuleBasicSetting } from './useModuleBasicSetting' export const MODULE_REMOVE_TYPE = { LEFT: 'left', @@ -20,6 +21,7 @@ export const MODULE_REMOVE_TYPE = { export function useModule() { const canvas = useRecoilValue(canvasState) const { swalFire } = useSwal() + const { checkModuleDisjointObjects } = useModuleBasicSetting() const moduleMove = (length, direction) => { const checkModuleDisjointSurface = (squarePolygon, turfModuleSetupSurface) => { @@ -38,6 +40,8 @@ export function useModule() { .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === selectedModules[0].surfaceId)[0] const isOverlapArray = [] const isInSurfaceArray = [] + const isOverlapObjects = [] + const objects = getObjects() if (selectedModules) { canvas.remove(...selectedModules) @@ -73,16 +77,28 @@ export function useModule() { //나갔는지 확인하는 로직 const isInSurface = turf.booleanContains(turfModuleSetupSurface, turfModule) || turf.booleanWithin(turfModule, turfModuleSetupSurface) isInSurfaceArray.push(isInSurface) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) }) const isNotOverlap = isOverlapArray.some((isOverlap) => isOverlap) // true면 겹침 const isNotOutSurface = isInSurfaceArray.every((isOutSurface) => isOutSurface) //false면 밖으로 나감 //안겹치고 안나갔으면 이동시킨다 아니면 원래 위치로 돌려놓는다 - if (isNotOverlap || !isNotOutSurface) { - selectedModules.forEach((module) => { - module.set({ ...module, left: module.originCoords.left, top: module.originCoords.top }) - module.setCoords() + if (isNotOverlap || !isNotOutSurface || isOverlapObjects.some((isOverlap) => isOverlap)) { + swalFire({ + title: isNotOverlap + ? '겹치는 모듈이 있습니다.' + : isOverlapObjects.some((isOverlap) => isOverlap) + ? '모듈이 오브젝트와 겹칩니다.' + : '영역 밖', + icon: 'error', + type: 'confirm', + confirmFn: () => { + selectedModules.forEach((module) => { + module.set({ ...module, left: module.originCoords.left, top: module.originCoords.top }) + module.setCoords() + }) + }, }) } @@ -95,11 +111,12 @@ export function useModule() { if (canvas.getActiveObjects().length === 0) return const activeModuleIds = canvas.getActiveObjects().map((obj) => obj.id) const modules = canvas.getObjects().filter((obj) => activeModuleIds.includes(obj.id)) + const objects = getObjects() const otherModules = canvas.getObjects().filter((obj) => obj.surfaceId === modules[0].surfaceId && obj.name === POLYGON_TYPE.MODULE) const moduleSetupSurface = canvas .getObjects() .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === modules[0].surfaceId)[0] - + let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] canvas.discardActiveObject() //선택해제 modules.forEach((module) => { const { top, left } = getPosotion(module, direction, length, true) @@ -109,20 +126,28 @@ export function useModule() { rect.setCoords() canvas.renderAll() - // const isOverlapOtherModules = otherModules.some((otherModule) => rect.intersectsWithObject(otherModule)) - const isOverlapOtherModules = otherModules.some( - (otherModule) => - turf.booleanOverlap(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)) || - turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)), + isOverlapOtherModules.push( + otherModules.some( + (otherModule) => + turf.booleanOverlap(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)) || + turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)), + ), ) - const isOutsideSurface = - !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(rect, true)) || - !turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(moduleSetupSurface, true)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(rect, true), objects)) - if (isOverlapOtherModules || isOutsideSurface) { + isOutsideSurface.push( + !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(rect, true)) || + !turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(moduleSetupSurface, true)), + ) + + if ( + isOverlapOtherModules.some((isOverlap) => isOverlap) || + isOutsideSurface.some((isOutside) => isOutside) || + isOverlapObjects.some((isOverlap) => isOverlap) + ) { swalFire({ - title: isOverlapOtherModules ? '겹치는 모듈이 있습니다.' : '영역 밖', + title: isOverlapOtherModules ? '겹치는 모듈이 있습니다.' : isOutsideSurface ? '모듈이 오브젝트와 겹칩니다.' : '영역 밖', icon: 'error', type: 'confirm', confirmFn: () => { @@ -133,6 +158,7 @@ export function useModule() { } }) } + const moduleMultiMove = (type, length, direction) => { if (canvas.getActiveObjects().length === 0) return if (canvas.getActiveObjects().length > 1) { @@ -148,6 +174,8 @@ export function useModule() { const modules = type === 'row' ? getRowModules(activeModule) : getColumnModules(activeModule) const otherModules = getOtherModules(modules) const objects = getObjects() + console.log('🚀 ~ moduleMultiMove ~ objects:', objects) + const moduleSetupSurface = canvas .getObjects() .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0] @@ -175,13 +203,7 @@ export function useModule() { } if (objects.length > 0) { - isOverlapObjects.push( - objects.some( - (object) => - turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)) || - turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)), - ), - ) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) } isOutsideSurface.push( @@ -196,7 +218,11 @@ export function useModule() { isOutsideSurface.some((isOutside) => isOutside) ) { swalFire({ - title: isOverlapOtherModules.some((isOverlap) => isOverlap) ? '겹치는 모듈이 있습니다.' : '영역 밖', + title: isOverlapOtherModules.some((isOverlap) => isOverlap) + ? '겹치는 모듈이 있습니다.' + : isOverlapObjects.some((isOverlap) => isOverlap) + ? '모듈이 오브젝트와 겹칩니다.' + : '영역 밖', icon: 'error', type: 'confirm', confirmFn: () => { @@ -232,9 +258,9 @@ export function useModule() { let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] modules.forEach((module) => { - const { top, left } = getPosotion(module, direction, length, true) + const { top, left } = getPosotion(module, direction, length, false) const moduleOptions = { ...module, left, top, id: uuidv4() } - const rect = new QPolygon(module.points, moduleOptions) + const rect = new QPolygon(module.getCurrentPoints(), moduleOptions) canvas.add(rect) copyRects.push(rect) module.setCoords() @@ -250,13 +276,7 @@ export function useModule() { } if (objects.length > 0) { - isOverlapObjects.push( - objects.some( - (object) => - turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)) || - turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)), - ), - ) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) } isOutsideSurface.push( @@ -271,7 +291,11 @@ export function useModule() { isOutsideSurface.some((isOutside) => isOutside) ) { swalFire({ - title: isOverlapOtherModules.some((isOverlap) => isOverlap) ? '겹치는 모듈이 있습니다.' : '영역 밖', + title: isOverlapOtherModules.some((isOverlap) => isOverlap) + ? '겹치는 모듈이 있습니다.' + : isOverlapObjects.some((isOverlap) => isOverlap) + ? '모듈이 오브젝트와 겹칩니다.' + : '영역 밖', icon: 'error', type: 'confirm', confirmFn: () => { @@ -284,35 +308,11 @@ export function useModule() { } } - const getIsOverlapOtherModules = (module, otherModules) => { - return otherModules.some( - (otherModule) => - turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(otherModule, true)) || - turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(otherModule, true)), - ) - } - - const getIsOverlapObjects = (module, objects) => { - return objects.some( - (object) => - turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)) || - turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)), - ) - } - - const getIsOutsideSurface = (module, moduleSetupSurface) => { - return ( - !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(module, true)) || - !turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(moduleSetupSurface, true)) - ) - } - const moduleColumnRemove = (type) => { const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] const columnModules = getColumnModules(activeModule) const otherModules = getOtherModules(columnModules) const objects = getObjects() - console.log('🚀 ~ moduleColumnRemove ~ objects:', objects) let targetModules = [] const rightModules = otherModules.filter((module) => activeModule.left < module.left).sort((a, b) => a.left - b.left) const leftModules = otherModules.filter((module) => activeModule.left > module.left).sort((a, b) => b.left - a.left) @@ -321,19 +321,11 @@ export function useModule() { .getObjects() .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0] let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] - console.log( - '🚀 ~ moduleColumnRemove ~ isOverlapOtherModules, isOverlapObjects, isOutsideSurface:', - isOverlapOtherModules, - isOverlapObjects, - isOutsideSurface, - ) - canvas.discardActiveObject() canvas.remove(...columnModules) canvas.renderAll() if (type === MODULE_REMOVE_TYPE.LEFT) { - console.log('🚀 ~ moduleColumnRemove ~ rightModules:', rightModules) rightModules.forEach((module) => { module.originPos = { left: module.left, @@ -344,7 +336,7 @@ export function useModule() { module.setCoords() canvas.renderAll() isOverlapOtherModules.push(getIsOverlapOtherModules(module, leftModules)) - isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) }) targetModules = rightModules @@ -359,7 +351,7 @@ export function useModule() { module.setCoords() canvas.renderAll() isOverlapOtherModules.push(getIsOverlapOtherModules(module, rightModules)) - isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) }) targetModules = leftModules @@ -394,19 +386,12 @@ export function useModule() { sideModules.filter((m) => m.id !== module.id), ), ) - isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) }) targetModules = sideModules } - console.log('🚀 ~ sideModules.forEach ~ objects:', objects) - console.log( - '🚀 ~ moduleColumnRemove ~ isOverlapOtherModules, isOverlapObjects, isOutsideSurface:', - isOverlapOtherModules, - isOverlapObjects, - isOutsideSurface, - ) if ( (isOverlapOtherModules.some((isOverlap) => isOverlap) || isOverlapObjects.some((isOverlap) => isOverlap) || @@ -414,9 +399,10 @@ export function useModule() { type !== MODULE_REMOVE_TYPE.NONE ) { swalFire({ - title: - isOverlapOtherModules.some((isOverlap) => isOverlap) || isOverlapObjects.some((isOverlap) => isOverlap) - ? '겹치는 모듈이 있습니다.' + title: isOverlapOtherModules.some((isOverlap) => isOverlap) + ? '겹치는 모듈이 있습니다.' + : isOverlapObjects.some((isOverlap) => isOverlap) + ? '모듈이 오브젝트와 겹칩니다.' : '영역 밖', icon: 'error', type: 'confirm', @@ -426,10 +412,10 @@ export function useModule() { module.set({ top: module.originPos.top, left: module.originPos.left }) module.setCoords() }) - canvas.renderAll() }, }) } + canvas.renderAll() } const moduleRowRemove = (type) => { @@ -461,7 +447,7 @@ export function useModule() { module.setCoords() canvas.renderAll() isOverlapOtherModules.push(getIsOverlapOtherModules(module, topModules)) - isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) }) targetModules = bottomModules @@ -476,7 +462,7 @@ export function useModule() { module.setCoords() canvas.renderAll() isOverlapOtherModules.push(getIsOverlapOtherModules(module, bottomModules)) - isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) }) targetModules = topModules @@ -512,7 +498,7 @@ export function useModule() { sideModules.filter((m) => m.id !== module.id), ), ) - isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) }) targetModules = sideModules @@ -525,9 +511,10 @@ export function useModule() { type !== MODULE_REMOVE_TYPE.NONE ) { swalFire({ - title: - isOverlapOtherModules.some((isOverlap) => isOverlap) || isOverlapObjects.some((isOverlap) => isOverlap) - ? '겹치는 모듈이 있습니다.' + title: isOverlapOtherModules.some((isOverlap) => isOverlap) + ? '겹치는 모듈이 있습니다.' + : isOverlapObjects.some((isOverlap) => isOverlap) + ? '모듈이 오브젝트와 겹칩니다.' : '영역 밖', icon: 'error', type: 'confirm', @@ -537,10 +524,10 @@ export function useModule() { module.set({ top: module.originPos.top, left: module.originPos.left }) module.setCoords() }) - canvas.renderAll() }, }) } + canvas.renderAll() } const getRowModules = (target) => { @@ -559,7 +546,7 @@ export function useModule() { top = Number(target.top) - Number(length) top = hasMargin ? top - Number(target.height) : top } else if (direction === 'down') { - top = Number(target.top) + Number(target.height) + Number(length) + top = Number(target.top) + Number(length) top = hasMargin ? top + Number(target.height) : top } else if (direction === 'left') { left = Number(target.left) - Number(length) @@ -584,6 +571,29 @@ export function useModule() { .filter((obj) => [BATCH_TYPE.OPENING, BATCH_TYPE.TRIANGLE_DORMER, BATCH_TYPE.PENTAGON_DORMER, BATCH_TYPE.SHADOW].includes(obj.name)) } + const getIsOverlapOtherModules = (module, otherModules) => { + return otherModules.some( + (otherModule) => + turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(otherModule, true)) || + turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(otherModule, true)), + ) + } + + const getIsOverlapObjects = (module, objects) => { + return !objects.some( + (object) => + turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)) || + turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)), + ) + } + + const getIsOutsideSurface = (module, moduleSetupSurface) => { + return ( + !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(module, true)) || + !turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(moduleSetupSurface, true)) + ) + } + return { moduleMove, moduleMultiMove, diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index c9b00b8a..cbd740bf 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -429,7 +429,8 @@ export function useModuleBasicSetting() { dormerTurfPolygon = batchObjectGroupToTurfPolygon(object) } else { //개구, 그림자 - dormerTurfPolygon = polygonToTurfPolygon(rectToPolygon(object)) + object.set({ points: rectToPolygon(object) }) + dormerTurfPolygon = polygonToTurfPolygon(object) } const intersection = turf.intersect(turf.featureCollection([dormerTurfPolygon, tempTurfModule])) //겹치는지 확인 @@ -566,35 +567,35 @@ export function useModuleBasicSetting() { return containsBatchObjects } - /** - * 도머나 개구가 모듈에 걸치는지 확인하는 로직 - * @param {*} squarePolygon - * @param {*} containsBatchObjects - * @returns - */ - const checkModuleDisjointObjects = (squarePolygon, containsBatchObjects) => { - let isDisjoint = false - - if (containsBatchObjects.length > 0) { - let convertBatchObject - //도머가 있으면 적용되는 로직 - isDisjoint = containsBatchObjects.every((batchObject) => { - if (batchObject.type === 'group') { - convertBatchObject = batchObjectGroupToTurfPolygon(batchObject) - } else { - convertBatchObject = polygonToTurfPolygon(batchObject) - } - /** - * 도머가 여러개일수있으므로 겹치는게 있다면... - * 안겹치는지 확인하는 로직이라 안겹치면 true를 반환 - */ - return turf.booleanDisjoint(squarePolygon, convertBatchObject) - }) - } else { - isDisjoint = true - } - return isDisjoint - } + // /** + // * 도머나 개구가 모듈에 걸치는지 확인하는 로직 + // * @param {*} squarePolygon + // * @param {*} containsBatchObjects + // * @returns + // */ + // const checkModuleDisjointObjects = (squarePolygon, containsBatchObjects) => { + // let isDisjoint = false + // + // if (containsBatchObjects.length > 0) { + // let convertBatchObject + // //도머가 있으면 적용되는 로직 + // isDisjoint = containsBatchObjects.every((batchObject) => { + // if (batchObject.type === 'group') { + // convertBatchObject = batchObjectGroupToTurfPolygon(batchObject) + // } else { + // convertBatchObject = polygonToTurfPolygon(batchObject) + // } + // /** + // * 도머가 여러개일수있으므로 겹치는게 있다면... + // * 안겹치는지 확인하는 로직이라 안겹치면 true를 반환 + // */ + // return turf.booleanDisjoint(squarePolygon, convertBatchObject) + // }) + // } else { + // isDisjoint = true + // } + // return isDisjoint + // } /** * 배치면 안에 있는지 확인 @@ -1997,36 +1998,6 @@ export function useModuleBasicSetting() { return containsBatchObjects } - /** - * 도머나 개구가 모듈에 걸치는지 확인하는 로직 - * @param {*} squarePolygon - * @param {*} containsBatchObjects - * @returns - */ - const checkModuleDisjointObjects = (squarePolygon, containsBatchObjects) => { - let isDisjoint = false - - if (containsBatchObjects.length > 0) { - let convertBatchObject - //도머가 있으면 적용되는 로직 - isDisjoint = containsBatchObjects.every((batchObject) => { - if (batchObject.type === 'group') { - convertBatchObject = batchObjectGroupToTurfPolygon(batchObject) - } else { - convertBatchObject = polygonToTurfPolygon(batchObject) - } - /** - * 도머가 여러개일수있으므로 겹치는게 있다면... - * 안겹치는지 확인하는 로직이라 안겹치면 true를 반환 - */ - return turf.booleanDisjoint(squarePolygon, convertBatchObject) - }) - } else { - isDisjoint = true - } - return isDisjoint - } - /** * 배치면 안에 있는지 확인 * @param {*} squarePolygon @@ -2287,6 +2258,39 @@ export function useModuleBasicSetting() { //드래그 하기위해 기능 활성화 } + /** + * 도머나 개구가 모듈에 걸치는지 확인하는 로직 + * @param {*} squarePolygon + * @param {*} containsBatchObjects + * @returns + */ + const checkModuleDisjointObjects = (squarePolygon, containsBatchObjects) => { + let isDisjoint = false + + if (containsBatchObjects.length > 0) { + let convertBatchObject + //도머가 있으면 적용되는 로직 + isDisjoint = containsBatchObjects.every((batchObject) => { + if (batchObject.type === 'group') { + convertBatchObject = batchObjectGroupToTurfPolygon(batchObject) + } else { + if (!batchObject.points) { + batchObject.set({ points: rectToPolygon(batchObject) }) + } + convertBatchObject = polygonToTurfPolygon(batchObject) + } + /** + * 도머가 여러개일수있으므로 겹치는게 있다면... + * 안겹치는지 확인하는 로직이라 안겹치면 true를 반환 + */ + return turf.booleanDisjoint(squarePolygon, convertBatchObject) + }) + } else { + isDisjoint = true + } + return isDisjoint + } + return { makeModuleInstArea, manualModuleSetup, @@ -2294,5 +2298,6 @@ export function useModuleBasicSetting() { restoreModuleInstArea, manualFlatroofModuleSetup, autoFlatroofModuleSetup, + checkModuleDisjointObjects, } } From ac8ec176a09d31bb568739b9fafb7d2cc537b3c5 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Fri, 27 Dec 2024 18:36:44 +0900 Subject: [PATCH 07/15] =?UTF-8?q?=F0=9F=93=8Cfix:=20=EC=86=8C=EC=8A=A4?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/QcastProvider.js | 2 +- src/components/floor-plan/CanvasFrame.jsx | 20 +++---- src/components/floor-plan/CanvasLayout.jsx | 4 +- src/components/floor-plan/CanvasMenu.jsx | 57 ++++++++----------- src/components/floor-plan/FloorPlan.jsx | 2 +- src/components/floor-plan/MenuDepth01.jsx | 5 +- .../floor-plan/RoofCoveringMenu.jsx | 7 ++- src/hooks/option/useCanvasSetting.js | 11 ---- 8 files changed, 44 insertions(+), 64 deletions(-) diff --git a/src/app/QcastProvider.js b/src/app/QcastProvider.js index 861ee8f9..43404308 100644 --- a/src/app/QcastProvider.js +++ b/src/app/QcastProvider.js @@ -1,6 +1,6 @@ 'use client' -import { createContext, useEffect, useState } from 'react' +import { createContext, useState } from 'react' import { ErrorBoundary } from 'next/dist/client/components/error-boundary' import { useCommonCode } from '@/hooks/common/useCommonCode' import ServerError from './error' diff --git a/src/components/floor-plan/CanvasFrame.jsx b/src/components/floor-plan/CanvasFrame.jsx index d21c55e7..cf2e0d56 100644 --- a/src/components/floor-plan/CanvasFrame.jsx +++ b/src/components/floor-plan/CanvasFrame.jsx @@ -1,32 +1,28 @@ 'use client' -import { useContext, useEffect, useRef } from 'react' +import { useEffect, useRef } from 'react' import { useRecoilValue } from 'recoil' +import QContextMenu from '@/components/common/context-menu/QContextMenu' +import PanelBatchStatistics from '@/components/floor-plan/modal/panelBatch/PanelBatchStatistics' +import ImgLoad from '@/components/floor-plan/modal/ImgLoad' import { useCanvas } from '@/hooks/useCanvas' -import { useEvent } from '@/hooks/useEvent' import { usePlan } from '@/hooks/usePlan' import { useContextMenu } from '@/hooks/useContextMenu' -import { currentMenuState } from '@/store/canvasAtom' -import QContextMenu from '@/components/common/context-menu/QContextMenu' import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize' -import { MENU } from '@/common/common' -import PanelBatchStatistics from '@/components/floor-plan/modal/panelBatch/PanelBatchStatistics' +import { currentMenuState } from '@/store/canvasAtom' import { totalDisplaySelector } from '@/store/settingAtom' -import ImgLoad from '@/components/floor-plan/modal/ImgLoad' +import { MENU } from '@/common/common' export default function CanvasFrame() { const canvasRef = useRef(null) - const { canvas, handleBackImageLoadToCanvas } = useCanvas('canvas') + const { canvas } = useCanvas('canvas') const { canvasLoadInit, gridInit } = useCanvasConfigInitialize() const currentMenu = useRecoilValue(currentMenuState) const { contextMenu, handleClick } = useContextMenu() - const { selectedPlan, currentCanvasPlan } = usePlan() + const { selectedPlan } = usePlan() const totalDisplay = useRecoilValue(totalDisplaySelector) // 집계표 표시 여부 - // useEvent() - // const { initEvent } = useContext(EventContext) - // initEvent() const loadCanvas = () => { if (canvas) { diff --git a/src/components/floor-plan/CanvasLayout.jsx b/src/components/floor-plan/CanvasLayout.jsx index 70bf2bb9..ba2994c0 100644 --- a/src/components/floor-plan/CanvasLayout.jsx +++ b/src/components/floor-plan/CanvasLayout.jsx @@ -3,12 +3,12 @@ import { useContext, useEffect } from 'react' import { useRecoilValue } from 'recoil' import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider' +import { SessionContext } from '@/app/SessionProvider' import { useMessage } from '@/hooks/useMessage' import { useSwal } from '@/hooks/useSwal' import { usePlan } from '@/hooks/usePlan' -import { globalLocaleStore } from '@/store/localeAtom' -import { SessionContext } from '@/app/SessionProvider' import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' +import { globalLocaleStore } from '@/store/localeAtom' export default function CanvasLayout({ children }) { // const { menuNumber } = props diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 71fdb0bf..9a420b01 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -2,54 +2,47 @@ import { useContext, useEffect, useState } from 'react' +import { usePathname, useRouter } from 'next/navigation' + import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' -import { usePathname, useRouter } from 'next/navigation' +import { v4 as uuidv4 } from 'uuid' + import MenuDepth01 from './MenuDepth01' import QSelectBox from '@/components/common/select/QSelectBox' -import { v4 as uuidv4 } from 'uuid' +import SettingModal01 from '@/components/floor-plan/modal/setting01/SettingModal01' +import PlacementShapeSetting from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' +import EstimateCopyPop from '../estimate/popup/EstimateCopyPop' +import DocDownOptionPop from '../estimate/popup/DocDownOptionPop' +import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider' import { useMessage } from '@/hooks/useMessage' import { usePlan } from '@/hooks/usePlan' import { useSwal } from '@/hooks/useSwal' import { useEvent } from '@/hooks/useEvent' +import { usePopup } from '@/hooks/usePopup' +import { useCanvasEvent } from '@/hooks/useCanvasEvent' +import { useCommonUtils } from '@/hooks/common/useCommonUtils' +import useMenu from '@/hooks/common/useMenu' +import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController' +import { useAxios } from '@/hooks/useAxios' +import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting' import { canvasSettingState, canvasState, canvasZoomState, currentMenuState, verticalHorizontalModeState } from '@/store/canvasAtom' import { sessionStore } from '@/store/commonAtom' import { outerLinePointsState } from '@/store/outerLineAtom' import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' -import { - addedRoofsSelector, - addedRoofsState, - basicSettingState, - roofMaterialsSelector, - selectedRoofMaterialSelector, - settingModalFirstOptionsState, -} from '@/store/settingAtom' +import { addedRoofsState, basicSettingState, selectedRoofMaterialSelector, settingModalFirstOptionsState } from '@/store/settingAtom' +import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom' +import { commonUtilsState } from '@/store/commonUtilsAtom' +import { menusState, menuTypeState } from '@/store/menuAtom' +import { estimateState, floorPlanObjectState } from '@/store/floorPlanObjectAtom' +import { pwrGnrSimTypeState } from '@/store/simulatorAtom' +import { isObjectNotEmpty } from '@/util/common-utils' import KO from '@/locales/ko.json' import JA from '@/locales/ja.json' -import { useCanvasEvent } from '@/hooks/useCanvasEvent' -import SettingModal01 from '@/components/floor-plan/modal/setting01/SettingModal01' -import { usePopup } from '@/hooks/usePopup' -import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom' -import PlacementShapeSetting from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' -import { useCommonUtils } from '@/hooks/common/useCommonUtils' -import { commonUtilsState } from '@/store/commonUtilsAtom' -import { menusState, menuTypeState } from '@/store/menuAtom' -import useMenu from '@/hooks/common/useMenu' import { MENU } from '@/common/common' -import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController' -import { estimateState, floorPlanObjectState } from '@/store/floorPlanObjectAtom' -import DocDownOptionPop from '../estimate/popup/DocDownOptionPop' -import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider' -import EstimateCopyPop from '../estimate/popup/EstimateCopyPop' -import { pwrGnrSimTypeState } from '@/store/simulatorAtom' -import { useAxios } from '@/hooks/useAxios' - -import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting' -import { isObjectNotEmpty } from '@/util/common-utils' - export default function CanvasMenu(props) { const { menuNumber, setMenuNumber } = props const pathname = usePathname() @@ -58,8 +51,8 @@ export default function CanvasMenu(props) { const canvasMenus = useRecoilValue(menusState) const [type, setType] = useRecoilState(menuTypeState) const [verticalHorizontalMode, setVerticalHorizontalMode] = useRecoilState(verticalHorizontalModeState) - const [appMessageState, setAppMessageState] = useRecoilState(appMessageStore) - const [currentMenu, setCurrentMenu] = useRecoilState(currentMenuState) + const [setAppMessageState] = useRecoilState(appMessageStore) + const [setCurrentMenu] = useRecoilState(currentMenuState) const setOuterLinePoints = useSetRecoilState(outerLinePointsState) const setPlacementPoints = useSetRecoilState(placementShapeDrawingPointsState) const canvasSetting = useRecoilValue(canvasSettingState) diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx index e2c53668..fe95d46b 100644 --- a/src/components/floor-plan/FloorPlan.jsx +++ b/src/components/floor-plan/FloorPlan.jsx @@ -1,6 +1,6 @@ 'use client' -import { useContext, useEffect } from 'react' +import { useEffect } from 'react' //import { useRecoilState } from 'recoil' import CanvasMenu from '@/components/floor-plan/CanvasMenu' import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' diff --git a/src/components/floor-plan/MenuDepth01.jsx b/src/components/floor-plan/MenuDepth01.jsx index 5b1897b3..1253c491 100644 --- a/src/components/floor-plan/MenuDepth01.jsx +++ b/src/components/floor-plan/MenuDepth01.jsx @@ -1,11 +1,12 @@ 'use client' +import { useEffect } from 'react' + import { useMessage } from '@/hooks/useMessage' +import useMenu from '@/hooks/common/useMenu' import { canvasState, currentMenuState } from '@/store/canvasAtom' import { useRecoilState, useRecoilValue } from 'recoil' import { menuTypeState, subMenusState } from '@/store/menuAtom' -import useMenu from '@/hooks/common/useMenu' -import { useEffect } from 'react' export default function MenuDepth01() { const type = useRecoilValue(menuTypeState) diff --git a/src/components/floor-plan/RoofCoveringMenu.jsx b/src/components/floor-plan/RoofCoveringMenu.jsx index 26da4bda..b270a1f2 100644 --- a/src/components/floor-plan/RoofCoveringMenu.jsx +++ b/src/components/floor-plan/RoofCoveringMenu.jsx @@ -1,11 +1,12 @@ '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' +import { useMessage } from '@/hooks/useMessage' +import { currentMenuState } from '@/store/canvasAtom' +import { modalState } from '@/store/modalAtom' export default function RoofCoveringMenu() { const { getMessage } = useMessage() diff --git a/src/hooks/option/useCanvasSetting.js b/src/hooks/option/useCanvasSetting.js index 441a06030..1c1dca34 100644 --- a/src/hooks/option/useCanvasSetting.js +++ b/src/hooks/option/useCanvasSetting.js @@ -269,17 +269,6 @@ export function useCanvasSetting() { roofSizeSet: item.roofSizeSet, roofAngleSet: item.roofAngleSet, } - - roofsArray = { - roofApply: true, - roofSeq: 1, - roofMatlCd: 'ROOF_ID_WA_53A', - roofWidth: 265, - roofHeight: 235, - roofHajebichi: 0, - roofGap: 'HEI_455', - roofLayout: 'P', - } }) } else { roofsRow = [ From dddb7261b7edac7a5213387da4d5a689f29e1105 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 30 Dec 2024 10:42:46 +0900 Subject: [PATCH 08/15] =?UTF-8?q?=F0=9F=9A=A8chore:=20pnpm=20=EC=98=B5?= =?UTF-8?q?=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 개발시 서버가 느려서 짜증나는 사람은 pnpm 써도 상관없습니다 --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 315cf207..f3b61bd7 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,5 @@ next-env.d.ts #lock files yarn.lock package-lock.json +pnpm-lock.yaml certificates \ No newline at end of file From 96ec93412de1122138b0b23356f51b65d42cb7a3 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 30 Dec 2024 10:46:51 +0900 Subject: [PATCH 09/15] =?UTF-8?q?=EC=A7=80=EB=B6=95=EB=A9=B4=20=ED=95=A0?= =?UTF-8?q?=EB=8B=B9=20=EC=9E=91=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/CanvasMenu.jsx | 11 +- .../ContextRoofAllocationSetting.jsx | 133 +++++++++--------- .../roofAllocation/RoofAllocationSetting.jsx | 3 +- .../roofcover/useRoofAllocationSetting.js | 58 ++++---- src/store/settingAtom.js | 4 +- 5 files changed, 107 insertions(+), 102 deletions(-) diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 9a420b01..b211b420 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -51,8 +51,8 @@ export default function CanvasMenu(props) { const canvasMenus = useRecoilValue(menusState) const [type, setType] = useRecoilState(menuTypeState) const [verticalHorizontalMode, setVerticalHorizontalMode] = useRecoilState(verticalHorizontalModeState) - const [setAppMessageState] = useRecoilState(appMessageStore) - const [setCurrentMenu] = useRecoilState(currentMenuState) + const setAppMessageState = useSetRecoilState(appMessageStore) + const setCurrentMenu = useSetRecoilState(currentMenuState) const setOuterLinePoints = useSetRecoilState(outerLinePointsState) const setPlacementPoints = useSetRecoilState(placementShapeDrawingPointsState) const canvasSetting = useRecoilValue(canvasSettingState) @@ -116,13 +116,6 @@ export default function CanvasMenu(props) { if (pathname !== '/floor-plan') router.push('/floor-plan') } - useEffect(() => { - console.log('addedRoofs', addedRoofs) - }, [addedRoofs]) - useEffect(() => { - console.log('selectedRoofMaterial', selectedRoofMaterial) - }, [selectedRoofMaterial]) - const changeSelectedRoofMaterial = (e) => { setBasicSetting({ ...basicSetting, selectedRoofMaterial: e }) } diff --git a/src/components/floor-plan/modal/roofAllocation/ContextRoofAllocationSetting.jsx b/src/components/floor-plan/modal/roofAllocation/ContextRoofAllocationSetting.jsx index cba18953..23993cb0 100644 --- a/src/components/floor-plan/modal/roofAllocation/ContextRoofAllocationSetting.jsx +++ b/src/components/floor-plan/modal/roofAllocation/ContextRoofAllocationSetting.jsx @@ -28,6 +28,7 @@ export default function ContextRoofAllocationSetting(props) { handleChangeRaft, handleChangeLayout, handleSaveContext, + currentRoofList, } = useRoofAllocationSetting(id) const { findCommonCode } = useCommonCode() @@ -39,7 +40,7 @@ export default function ContextRoofAllocationSetting(props) { return ( -
+

{getMessage('plan.menu.estimate.roof.alloc')}

- {roofList.map((roof, index) => { + {currentRoofList.map((roof, index) => { return (
@@ -88,78 +93,74 @@ export default function ContextRoofAllocationSetting(props) {
r.id === roof.id)} + value={roof} + showKey={'roofMatlNm'} + sourceKey={'roofMatlCd'} + targetKey={'roofMatlCd'} onChange={(e) => handleChangeRoofMaterial(e, index)} />
- {index === 0 && 基本屋根材} + {index === 0 && {getMessage('modal.roof.alloc.default.roof.material')}} {index !== 0 && }
-
- {roof.widAuth && ( -
- W -
- + {(roof.widAuth || roof.lenAuth) && ( +
+ {roof.widAuth && ( +
+ W +
+ +
- {/*
- -
*/} -
- )} - {roof.lenAuth && ( -
- L -
- + )} + {roof.lenAuth && ( +
+ L +
+ +
- {/*
- -
*/} -
- )} - {roof.raftAuth && ( -
- {getMessage('modal.placement.initial.setting.rafter')} -
- {raftCodes.length > 0 && ( - ({ name: raft.clCodeNm, value: raft.clCode }))} - onChange={(e) => handleChangeRaft(e, index)} - value={raftCodes.find((r) => r.value === roof.raft)} - /> - )} - {/* */} + )} +
+ )} + {(roof.raftAuth || roof.roofPchAuth) && ( +
+ {roof.raftAuth && ( +
+
+ {getMessage('modal.placement.initial.setting.rafter')} + {raftCodes.length > 0 && ( +
+ +
+ )} +
-
- )} - {roof.roofPchAuth && ( -
- {getMessage('hajebichi')} -
- + )} + {roof.roofPchAuth && ( +
+
+ {getMessage('hajebichi')} +
+ +
+
- {/*
- -
*/} -
- )} -
+ )} +
+ )}
- {roofList.map((roof, index) => { + {currentRoofList.map((roof, index) => { return (
diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index a2c7b483..c48a8d7a 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -13,6 +13,7 @@ import useMenu from '@/hooks/common/useMenu' import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' import { menuTypeState } from '@/store/menuAtom' import { useRoofFn } from '@/hooks/common/useRoofFn' +import { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' // 지붕면 할당 export function useRoofAllocationSetting(id) { @@ -32,7 +33,7 @@ export function useRoofAllocationSetting(id) { const [currentRoofMaterial, setCurrentRoofMaterial] = useState(roofMaterials[0]) // 팝업 내 기준 지붕재 const [roofList, setRoofList] = useRecoilState(addedRoofsState) // 배치면 초기설정에서 선택한 지붕재 배열 const [editingLines, setEditingLines] = useState([]) - const isFirstRef = useRef(0) + const [currentRoofList, setCurrentRoofList] = useState(roofList) const { setSurfaceShapePattern } = useRoofFn() @@ -76,20 +77,25 @@ export function useRoofAllocationSetting(id) { }, []) const onAddRoofMaterial = () => { - if (roofList.length >= 4) { + if (currentRoofList.length >= 4) { swalFire({ type: 'alert', icon: 'error', text: getMessage('지붕재는 4개까지 선택 가능합니다.') }) return } - setRoofList([...roofList, { ...currentRoofMaterial, selected: false, id: currentRoofMaterial.roofMatlCd, name: currentRoofMaterial.roofMatlNm }]) + setCurrentRoofList([ + ...currentRoofList, + { ...currentRoofMaterial, selected: false, id: currentRoofMaterial.roofMatlCd, name: currentRoofMaterial.roofMatlNm }, + ]) } const onDeleteRoofMaterial = (idx) => { - setRoofList([...roofList.filter((_, index) => index !== idx)]) + const isSelected = currentRoofList[idx].selected + const newRoofList = [...currentRoofList].filter((_, index) => index !== idx) + if (isSelected) { + newRoofList[0].selected = true + } + setCurrentRoofList(newRoofList) } - const { handleMenu } = useMenu() - const [currentMenu, setCurrentMenu] = useRecoilState(currentMenuState) - // 선택한 지붕재로 할당 const handleSave = () => { // 모두 actualSize 있으면 바로 적용 없으면 actualSize 설정 @@ -102,7 +108,7 @@ export function useRoofAllocationSetting(id) { // 지붕재 오른쪽 마우스 클릭 후 단일로 지붕재 변경 필요한 경우 const handleSaveContext = () => { - const selectedRoofMaterial = roofList.find((roof) => roof.selected) + const selectedRoofMaterial = currentRoofList.find((roof) => roof.selected) setSurfaceShapePattern(currentObject, roofDisplay.column, false, selectedRoofMaterial) closeAll() } @@ -169,11 +175,11 @@ export function useRoofAllocationSetting(id) { setBasicSetting((prev) => { return { ...prev, - selectedRoofMaterial: roofList.find((roof) => roof.selected), + selectedRoofMaterial: currentRoofList.find((roof) => roof.selected), } }) - setRoofList(roofList) + setRoofList(currentRoofList) const roofs = canvas.getObjects().filter((obj) => obj.name === 'roof') @@ -182,7 +188,12 @@ export function useRoofAllocationSetting(id) { roof.set({ isFixed: true, }) - setSurfaceShapePattern(roof, roofDisplay.column) + setSurfaceShapePattern( + roof, + roofDisplay.column, + false, + currentRoofList.find((roof) => roof.selected), + ) drawDirectionArrow(roof) }) @@ -216,54 +227,53 @@ export function useRoofAllocationSetting(id) { // 지붕재 변경 const handleChangeRoofMaterial = (value, index) => { - if (isFirstRef.current === 0) { - isFirstRef.current++ - return - } + const selectedIndex = roofMaterials.findIndex((roof) => roof.selected) const selectedRoofMaterial = roofMaterials.find((roof) => roof.roofMatlCd === value.id) - const newRoofList = roofList.map((roof, idx) => { + const newRoofList = currentRoofList.map((roof, idx) => { if (idx === index) { return { ...selectedRoofMaterial } } return roof }) - setRoofList(newRoofList) + newRoofList[selectedIndex].selected = true + + setCurrentRoofList(newRoofList) } // 기본 지붕재 radio값 변경 const handleDefaultRoofMaterial = (index) => { - const newRoofList = roofList.map((roof, idx) => { + const newRoofList = currentRoofList.map((roof, idx) => { return { ...roof, selected: idx === index } }) - setRoofList(newRoofList) + setCurrentRoofList(newRoofList) } // 서까래 변경 const handleChangeRaft = (e, index) => { const raftValue = e.value - const newRoofList = roofList.map((roof, idx) => { + const newRoofList = currentRoofList.map((roof, idx) => { if (idx === index) { return { ...roof, raft: raftValue } } return roof }) - setRoofList(newRoofList) + setCurrentRoofList(newRoofList) } const handleChangeLayout = (layoutValue, index) => { - const newRoofList = roofList.map((roof, idx) => { + const newRoofList = currentRoofList.map((roof, idx) => { if (idx === index) { return { ...roof, layout: layoutValue } } return roof }) - setRoofList(newRoofList) + setCurrentRoofList(newRoofList) } return { @@ -278,11 +288,11 @@ export function useRoofAllocationSetting(id) { setBasicSetting, currentRoofMaterial, setCurrentRoofMaterial, - roofList, handleDefaultRoofMaterial, handleChangeRoofMaterial, handleChangeRaft, handleChangeLayout, handleSaveContext, + currentRoofList, } } diff --git a/src/store/settingAtom.js b/src/store/settingAtom.js index 2350b0f5..df5022a7 100644 --- a/src/store/settingAtom.js +++ b/src/store/settingAtom.js @@ -224,9 +224,9 @@ export const roofMaterialsAtom = atom({ export const selectedRoofMaterialSelector = selector({ key: 'selectedRoofMaterialSelector', get: ({ get }) => { - const basicSetting = get(basicSettingState) + const addedRoofs = get(addedRoofsState) - return { ...basicSetting.selectedRoofMaterial } + return addedRoofs.find((roof) => roof.selected) }, }) From 860ddec138a0e1a623f0fb45f7efd1098919a38b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=8B=9D?= <43837214+Minsiki@users.noreply.github.com> Date: Mon, 30 Dec 2024 10:55:13 +0900 Subject: [PATCH 10/15] module copy, move --- .../modal/module/column/ColumnInsert.jsx | 32 ++++++--- src/hooks/module/useModule.js | 65 ++++++++++++++++++- 2 files changed, 86 insertions(+), 11 deletions(-) diff --git a/src/components/floor-plan/modal/module/column/ColumnInsert.jsx b/src/components/floor-plan/modal/module/column/ColumnInsert.jsx index 8239dc33..56f9a66c 100644 --- a/src/components/floor-plan/modal/module/column/ColumnInsert.jsx +++ b/src/components/floor-plan/modal/module/column/ColumnInsert.jsx @@ -5,20 +5,22 @@ import { usePopup } from '@/hooks/usePopup' import { useMessage } from '@/hooks/useMessage' import { useState } from 'react' import Image from 'next/image' +import { MODULE_INSERT_TYPE, useModule } from '@/hooks/module/useModule' export default function ColumnInsert(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) const { id, pos = contextPopupPosition, apply } = props const { closePopup } = usePopup() - const [selectedType, setSelectedType] = useState(1) + const [selectedType, setSelectedType] = useState(MODULE_INSERT_TYPE.LEFT) const { getMessage } = useMessage() + const { moduleColumnInsert } = useModule() const handleApply = () => { - if (apply) apply() + moduleColumnInsert(selectedType) closePopup(id) } - const HandleRadioChange = (e) => { - setSelectedType(Number(e.target.value)) + const handleRadioChange = (e) => { + setSelectedType(e.target.value) } return ( @@ -36,16 +38,30 @@ export default function ColumnInsert(props) {
- +
- +
- {selectedType === 1 && ( + {selectedType === MODULE_INSERT_TYPE.LEFT && ( react )} - {selectedType === 2 && ( + {selectedType === MODULE_INSERT_TYPE.RIGHT && ( react obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === modules[0].surfaceId)[0] let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] + let moduleLength = 0 + if (type === 'column') { + moduleLength = Number(modules[modules.length - 1].top) + Number(modules[modules.length - 1].height) - Number(modules[0].top) + } else if (type === 'row') { + moduleLength = Number(modules[modules.length - 1].left) + Number(modules[modules.length - 1].width) - Number(modules[0].left) + } + console.log('🚀 ~ moduleMultiCopy ~ modules:', modules) + console.log('🚀 ~ moduleMultiCopy ~ moduleLength:', moduleLength) modules.forEach((module) => { - const { top, left } = getPosotion(module, direction, length, false) + const { top, left } = getPosotion(module, direction, Number(length) + Number(moduleLength), false) + console.log('🚀 ~ modules.forEach ~ top:', top) const moduleOptions = { ...module, left, top, id: uuidv4() } const rect = new QPolygon(module.getCurrentPoints(), moduleOptions) canvas.add(rect) @@ -529,13 +545,55 @@ export function useModule() { } canvas.renderAll() } + // 좌우 열 옮기고 current Column 복사하기. + const moduleColumnInsert = (type) => { + const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] + const columnModules = getColumnModules(activeModule) + const otherModules = getOtherModules(columnModules) + const targetModules = + type === MODULE_INSERT_TYPE.LEFT + ? otherModules.filter((module) => module.left < activeModule.left).sort((a, b) => a.left - b.left) + : otherModules.filter((module) => module.left > activeModule.left).sort((a, b) => b.left - a.left) + const objects = getObjects() + const copyRects = [] + const moduleSetupSurface = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0] + let width = -1 + let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] + + targetModules.forEach((module) => { + if (width === -1) width = type === MODULE_INSERT_TYPE.LEFT ? module.left - activeModule.left : activeModule.left - module.left + const { left } = getPosotion(module, type, width, false) + const moduleOptions = { ...module, left, top, id: uuidv4() } + module.set({ left }) + // const rect = new QPolygon(module.getCurrentPoints(), moduleOptions) + // canvas.add(rect) + // copyRects.push(rect) + module.setCoords() + }) + // columnModules.forEach((module) => { + // const { top, left } = getPosotion(module, MODULE_INSERT_TYPE.LEFT, module.width, false) + // const moduleOptions = { ...module, left, top, id: uuidv4() } + // const rect = new QPolygon(module.getCurrentPoints(), moduleOptions) + // canvas.add(rect) + // copyRects.push(rect) + // module.setCoords() + // }) + } const getRowModules = (target) => { - return canvas.getObjects().filter((obj) => target.surfaceId === obj.surfaceId && obj.name === POLYGON_TYPE.MODULE && obj.top === target.top) + return canvas + .getObjects() + .filter((obj) => target.surfaceId === obj.surfaceId && obj.name === POLYGON_TYPE.MODULE && obj.top === target.top) + .sort((a, b) => a.left - b.left) } const getColumnModules = (target) => { - return canvas.getObjects().filter((obj) => target.surfaceId === obj.surfaceId && obj.name === POLYGON_TYPE.MODULE && obj.left === target.left) + return canvas + .getObjects() + .filter((obj) => target.surfaceId === obj.surfaceId && obj.name === POLYGON_TYPE.MODULE && obj.left === target.left) + .sort((a, b) => a.top - b.top) } const getPosotion = (target, direction, length, hasMargin = false) => { @@ -601,5 +659,6 @@ export function useModule() { moduleMultiCopy, moduleColumnRemove, moduleRowRemove, + moduleColumnInsert, } } From 6414a1116c81f77adfc8090b830eff0b93a04b15 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 30 Dec 2024 11:11:52 +0900 Subject: [PATCH 11/15] =?UTF-8?q?=EC=84=9C=EA=B9=8C=EB=9E=98=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EC=95=88=EB=90=98=EB=8A=94=20=ED=98=84=EC=83=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx | 1 + src/hooks/roofcover/useRoofAllocationSetting.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx b/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx index 1b98044a..a949fd2e 100644 --- a/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx +++ b/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx @@ -137,6 +137,7 @@ export default function RoofAllocationSetting(props) { showKey={'clCodeNm'} sourceKey={'clCode'} targetKey={roof.raft ? 'raft' : 'raftBaseCd'} + onChange={(e) => handleChangeRaft(e, index)} />
)} diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index c48a8d7a..6c1ace5c 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -253,7 +253,7 @@ export function useRoofAllocationSetting(id) { // 서까래 변경 const handleChangeRaft = (e, index) => { - const raftValue = e.value + const raftValue = e.clCode const newRoofList = currentRoofList.map((roof, idx) => { if (idx === index) { From 3907624dac96a284a84cb8b43d952453b23bfd9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=8B=9D?= <43837214+Minsiki@users.noreply.github.com> Date: Mon, 30 Dec 2024 15:13:11 +0900 Subject: [PATCH 12/15] =?UTF-8?q?=EC=97=B4.=20=EB=8B=A8=20=EC=82=BD?= =?UTF-8?q?=EC=9E=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/module/row/RowInsert.jsx | 30 ++- src/hooks/module/useModule.js | 221 +++++++++++++++--- 2 files changed, 218 insertions(+), 33 deletions(-) diff --git a/src/components/floor-plan/modal/module/row/RowInsert.jsx b/src/components/floor-plan/modal/module/row/RowInsert.jsx index 42ce1a31..613fb180 100644 --- a/src/components/floor-plan/modal/module/row/RowInsert.jsx +++ b/src/components/floor-plan/modal/module/row/RowInsert.jsx @@ -5,20 +5,22 @@ import { useRecoilValue } from 'recoil' import { contextPopupPositionState } from '@/store/popupAtom' import { usePopup } from '@/hooks/usePopup' import { useMessage } from '@/hooks/useMessage' +import { MODULE_INSERT_TYPE, useModule } from '@/hooks/module/useModule' export default function RowInsert(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) const { id, pos = contextPopupPosition, apply } = props const { closePopup } = usePopup() - const [selectedType, setSelectedType] = useState(1) + const [selectedType, setSelectedType] = useState(MODULE_INSERT_TYPE.TOP) const { getMessage } = useMessage() + const { muduleRowInsert } = useModule() const handleApply = () => { - if (apply) apply() + muduleRowInsert(selectedType) closePopup(id) } const HandleRadioChange = (e) => { - setSelectedType(Number(e.target.value)) + setSelectedType(e.target.value) } return ( @@ -36,16 +38,30 @@ export default function RowInsert(props) {
- +
- +
- {selectedType === 1 && ( + {selectedType === MODULE_INSERT_TYPE.TOP && ( react )} - {selectedType === 2 && ( + {selectedType === MODULE_INSERT_TYPE.BOTTOM && ( react obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === modules[0].surfaceId)[0] let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] let moduleLength = 0 - if (type === 'column') { + if (['up', 'down'].includes(direction)) { moduleLength = Number(modules[modules.length - 1].top) + Number(modules[modules.length - 1].height) - Number(modules[0].top) - } else if (type === 'row') { + } else if (['left', 'right'].includes(direction)) { moduleLength = Number(modules[modules.length - 1].left) + Number(modules[modules.length - 1].width) - Number(modules[0].left) } - console.log('🚀 ~ moduleMultiCopy ~ modules:', modules) - console.log('🚀 ~ moduleMultiCopy ~ moduleLength:', moduleLength) modules.forEach((module) => { const { top, left } = getPosotion(module, direction, Number(length) + Number(moduleLength), false) - console.log('🚀 ~ modules.forEach ~ top:', top) const moduleOptions = { ...module, left, top, id: uuidv4() } const rect = new QPolygon(module.getCurrentPoints(), moduleOptions) canvas.add(rect) @@ -545,41 +542,212 @@ export function useModule() { } canvas.renderAll() } - // 좌우 열 옮기고 current Column 복사하기. + const moduleColumnInsert = (type) => { const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] const columnModules = getColumnModules(activeModule) - const otherModules = getOtherModules(columnModules) + let otherModules = getOtherModules(columnModules) const targetModules = type === MODULE_INSERT_TYPE.LEFT ? otherModules.filter((module) => module.left < activeModule.left).sort((a, b) => a.left - b.left) : otherModules.filter((module) => module.left > activeModule.left).sort((a, b) => b.left - a.left) const objects = getObjects() - const copyRects = [] + const copyModules = [] const moduleSetupSurface = canvas .getObjects() .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0] let width = -1 let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] - + if (targetModules.length === 0) { + swalFire({ + title: '마지막 모듈입니다.', + icon: 'error', + type: 'alert', + }) + return + } + canvas.discardActiveObject() targetModules.forEach((module) => { - if (width === -1) width = type === MODULE_INSERT_TYPE.LEFT ? module.left - activeModule.left : activeModule.left - module.left - const { left } = getPosotion(module, type, width, false) - const moduleOptions = { ...module, left, top, id: uuidv4() } - module.set({ left }) - // const rect = new QPolygon(module.getCurrentPoints(), moduleOptions) - // canvas.add(rect) - // copyRects.push(rect) + if (width === -1) + width = type === MODULE_INSERT_TYPE.LEFT ? Number(activeModule.left) - Number(module.left) : Number(module.left) - Number(activeModule.left) + const { top, left } = getPosotion(module, type, width, false) + module.originPos = { + left: module.left, + top: module.top, + } + module.set({ left, top }) + canvas.renderAll() + if (objects.length > 0) { + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) + } + + isOutsideSurface.push( + !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(module, true)) || + !turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(moduleSetupSurface, true)), + ) module.setCoords() }) - // columnModules.forEach((module) => { - // const { top, left } = getPosotion(module, MODULE_INSERT_TYPE.LEFT, module.width, false) - // const moduleOptions = { ...module, left, top, id: uuidv4() } - // const rect = new QPolygon(module.getCurrentPoints(), moduleOptions) - // canvas.add(rect) - // copyRects.push(rect) - // module.setCoords() - // }) + otherModules = getOtherModules(columnModules) + columnModules.forEach((module) => { + const { top, left } = getPosotion(module, type, width, false) + const moduleOptions = { ...module, left, top, id: uuidv4() } + const copyModule = new QPolygon(module.points, moduleOptions) + canvas.add(copyModule) + copyModules.push(copyModule) + canvas.renderAll() + + if (otherModules.length > 0) { + isOverlapOtherModules.push( + otherModules.some( + (otherModule) => + turf.booleanOverlap(polygonToTurfPolygon(copyModule, true), polygonToTurfPolygon(otherModule, true)) || + turf.booleanWithin(polygonToTurfPolygon(copyModule, true), polygonToTurfPolygon(otherModule, true)), + ), + ) + } + + if (objects.length > 0) { + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) + } + + isOutsideSurface.push( + !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(copyModule, true)) || + !turf.booleanWithin(polygonToTurfPolygon(copyModule, true), polygonToTurfPolygon(moduleSetupSurface, true)), + ) + module.setCoords() + }) + + if ( + isOverlapOtherModules.some((isOverlap) => isOverlap) || + isOverlapObjects.some((isOverlap) => isOverlap) || + isOutsideSurface.some((isOutside) => isOutside) + ) { + swalFire({ + title: isOverlapOtherModules.some((isOverlap) => isOverlap) + ? '겹치는 모듈이 있습니다.' + : isOverlapObjects.some((isOverlap) => isOverlap) + ? '모듈이 오브젝트와 겹칩니다.' + : '영역 밖', + icon: 'error', + type: 'confirm', + confirmFn: () => { + targetModules.forEach((module) => { + module.set({ top: module.originPos.top, left: module.originPos.left }) + module.setCoords() + }) + canvas.renderAll() + copyModules.forEach((module) => { + canvas.remove(module) + }) + canvas.renderAll() + }, + }) + } + } + + const muduleRowInsert = (type) => { + console.log('🚀 ~ muduleRowInsert ~ type:', type) + const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] + const rowModules = getRowModules(activeModule) + console.log('🚀 ~ muduleRowInsert ~ rowModules:', rowModules) + let otherModules = getOtherModules(rowModules) + const targetModules = + type === MODULE_INSERT_TYPE.TOP + ? otherModules.filter((module) => module.top < activeModule.top).sort((a, b) => b.top - a.top) + : otherModules.filter((module) => module.top > activeModule.top).sort((a, b) => a.top - b.top) + console.log('🚀 ~ muduleRowInsert ~ targetModules:', targetModules) + if (targetModules.length === 0) { + swalFire({ + title: '마지막 모듈입니다.', + icon: 'error', + type: 'alert', + }) + return + } + const objects = getObjects() + const copyModules = [] + const moduleSetupSurface = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0] + let height = -1 + let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] + canvas.discardActiveObject() + targetModules.forEach((module) => { + if (height === -1) + height = type === MODULE_INSERT_TYPE.TOP ? Number(activeModule.top) - Number(module.top) : Number(module.top) - Number(activeModule.top) + const { top, left } = getPosotion(module, type, height, false) + module.originPos = { + left: module.left, + top: module.top, + } + module.set({ left, top }) + canvas.renderAll() + if (objects.length > 0) { + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) + } + + isOutsideSurface.push( + !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(module, true)) || + !turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(moduleSetupSurface, true)), + ) + module.setCoords() + }) + otherModules = getOtherModules(rowModules) + rowModules.forEach((module) => { + const { top, left } = getPosotion(module, type, height, false) + const moduleOptions = { ...module, left, top, id: uuidv4() } + const copyModule = new QPolygon(module.points, moduleOptions) + canvas.add(copyModule) + copyModules.push(copyModule) + canvas.renderAll() + + if (otherModules.length > 0) { + isOverlapOtherModules.push( + otherModules.some( + (otherModule) => + turf.booleanOverlap(polygonToTurfPolygon(copyModule, true), polygonToTurfPolygon(otherModule, true)) || + turf.booleanWithin(polygonToTurfPolygon(copyModule, true), polygonToTurfPolygon(otherModule, true)), + ), + ) + } + + if (objects.length > 0) { + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) + } + + isOutsideSurface.push( + !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(copyModule, true)) || + !turf.booleanWithin(polygonToTurfPolygon(copyModule, true), polygonToTurfPolygon(moduleSetupSurface, true)), + ) + module.setCoords() + }) + + if ( + isOverlapOtherModules.some((isOverlap) => isOverlap) || + isOverlapObjects.some((isOverlap) => isOverlap) || + isOutsideSurface.some((isOutside) => isOutside) + ) { + swalFire({ + title: isOverlapOtherModules.some((isOverlap) => isOverlap) + ? '겹치는 모듈이 있습니다.' + : isOverlapObjects.some((isOverlap) => isOverlap) + ? '모듈이 오브젝트와 겹칩니다.' + : '영역 밖', + icon: 'error', + type: 'confirm', + confirmFn: () => { + targetModules.forEach((module) => { + module.set({ top: module.originPos.top, left: module.originPos.left }) + module.setCoords() + }) + canvas.renderAll() + copyModules.forEach((module) => { + canvas.remove(module) + }) + canvas.renderAll() + }, + }) + } } const getRowModules = (target) => { @@ -660,5 +828,6 @@ export function useModule() { moduleColumnRemove, moduleRowRemove, moduleColumnInsert, + muduleRowInsert, } } From 76c104302fd5a1e4178bd46a654ba2880e55d93a Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 30 Dec 2024 16:07:49 +0900 Subject: [PATCH 13/15] =?UTF-8?q?contextMenu=20=EC=A7=80=EB=B6=95=EC=9E=AC?= =?UTF-8?q?=20=EC=82=AD=EC=A0=9C,=20=EC=A7=80=EB=B6=95=EC=9E=AC=20?= =?UTF-8?q?=EC=A0=84=EC=B2=B4=20=EC=82=AD=EC=A0=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/common/useRoofFn.js | 23 +++++++++++++++++++++-- src/hooks/useContextMenu.js | 4 ++++ src/store/settingAtom.js | 10 ---------- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/hooks/common/useRoofFn.js b/src/hooks/common/useRoofFn.js index afe1c71e..eb932106 100644 --- a/src/hooks/common/useRoofFn.js +++ b/src/hooks/common/useRoofFn.js @@ -1,11 +1,13 @@ import { useRecoilValue } from 'recoil' -import { canvasState } from '@/store/canvasAtom' +import { canvasState, currentObjectState } from '@/store/canvasAtom' import { selectedRoofMaterialSelector } from '@/store/settingAtom' import { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' +import { POLYGON_TYPE } from '@/common/common' export function useRoofFn() { const canvas = useRecoilValue(canvasState) const selectedRoofMaterial = useRecoilValue(selectedRoofMaterialSelector) + const currentObject = useRecoilValue(currentObjectState) //면형상 선택 클릭시 지붕 패턴 입히기 function setSurfaceShapePattern(polygon, mode = 'onlyBorder', trestleMode = false, roofMaterial = selectedRoofMaterial) { @@ -141,5 +143,22 @@ export function useRoofFn() { polygon.roofMaterial = roofMaterial polygon.canvas?.renderAll() } - return { setSurfaceShapePattern } + + function removeRoofMaterial(roof = currentObject) { + if (roof === null || roof.name !== POLYGON_TYPE.ROOF) { + return + } + roof.set('fill', null) + roof.roofMaterial = null + canvas?.renderAll() + } + + function removeAllRoofMaterial() { + const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) + roofBases.forEach((roofBase) => { + removeRoofMaterial(roofBase) + }) + } + + return { setSurfaceShapePattern, removeRoofMaterial, removeAllRoofMaterial } } diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index ad662534..e0a2cf0f 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -36,6 +36,7 @@ import { fontSelector, globalFontAtom } from '@/store/fontAtom' import { useLine } from '@/hooks/useLine' import { useSwal } from '@/hooks/useSwal' import ContextRoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/ContextRoofAllocationSetting' +import { useRoofFn } from '@/hooks/common/useRoofFn' export function useContextMenu() { const canvas = useRecoilValue(canvasState) @@ -59,6 +60,7 @@ export function useContextMenu() { const { addLine, removeLine } = useLine() const commonTextFont = useRecoilValue(fontSelector('commonText')) const { swalFire } = useSwal() + const { removeRoofMaterial, removeAllRoofMaterial } = useRoofFn() const currentMenuSetting = () => { switch (currentMenu) { @@ -110,10 +112,12 @@ export function useContextMenu() { { id: 'roofMaterialRemove', name: getMessage('contextmenu.roof.material.remove'), + fn: () => removeRoofMaterial(), }, { id: 'roofMaterialRemoveAll', name: getMessage('contextmenu.roof.material.remove.all'), + fn: () => removeAllRoofMaterial(), }, { id: 'selectMove', diff --git a/src/store/settingAtom.js b/src/store/settingAtom.js index df5022a7..1b837fdd 100644 --- a/src/store/settingAtom.js +++ b/src/store/settingAtom.js @@ -239,16 +239,6 @@ export const roofMaterialsSelector = selector({ }, }) -// 지붕면 할당에서 추가된 지붕재 목록 -export const addedRoofsSelector = selector({ - key: 'addedRoofsSelector', - get: ({ get }) => { - const basicSetting = get(basicSettingState) - return basicSetting.roofs - }, - dangerouslyAllowMutability: true, -}) - /** * 현재 선택된 물건 번호 */ From e9fd8531386e6cbc503035ecdcc789f515ff81a7 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 30 Dec 2024 18:06:34 +0900 Subject: [PATCH 14/15] =?UTF-8?q?=EC=9C=A1=EC=A7=80=EB=B6=95=EC=9D=B8=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=20disabled=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/placementShape/PlacementShapeSetting.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx index 77d49d5e..a36f0cb4 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx @@ -247,6 +247,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set sourceKey="id" targetKey="id" showKey="name" + disabled={basicSetting.roofSizeSet === '3'} /> {/* {raftCodes.map((raft, index) => { From 28589aefb39cb52efe2da9dc2c23a7e9d2f1c6a6 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 30 Dec 2024 18:21:34 +0900 Subject: [PATCH 15/15] =?UTF-8?q?=EB=A9=94=EB=89=B4=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=A7=80=EB=B6=95=EC=9E=AC=20=EC=84=A0=ED=83=9D=20=EC=8B=9C=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=ED=95=9C=20=EC=A7=80=EB=B6=95=20default?= =?UTF-8?q?=EB=A1=9C=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/CanvasMenu.jsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index b211b420..34a7b6c4 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -79,7 +79,7 @@ export default function CanvasMenu(props) { const { floorPlanState, setFloorPlanState } = useContext(FloorPlanContext) const { restoreModuleInstArea } = useModuleBasicSetting() - const addedRoofs = useRecoilValue(addedRoofsState) + const [addedRoofs, setAddedRoofsState] = useRecoilState(addedRoofsState) const [basicSetting, setBasicSetting] = useRecoilState(basicSettingState) const selectedRoofMaterial = useRecoilValue(selectedRoofMaterialSelector) @@ -118,6 +118,16 @@ export default function CanvasMenu(props) { const changeSelectedRoofMaterial = (e) => { setBasicSetting({ ...basicSetting, selectedRoofMaterial: e }) + + const newAddedRoofs = addedRoofs.map((roof) => { + if (roof.index === e.index) { + return { ...roof, selected: true } + } else { + return { ...roof, selected: false } + } + }) + + setAddedRoofsState(newAddedRoofs) } const settingsModalOptions = useRecoilState(settingModalFirstOptionsState)