diff --git a/src/components/floor-plan/modal/module/PanelEdit.jsx b/src/components/floor-plan/modal/module/PanelEdit.jsx index dccedba2..5d38f9a8 100644 --- a/src/components/floor-plan/modal/module/PanelEdit.jsx +++ b/src/components/floor-plan/modal/module/PanelEdit.jsx @@ -14,7 +14,9 @@ import { useModule } from '@/hooks/module/useModule' export const PANEL_EDIT_TYPE = { MOVE: 'move', + MOVE_ALL: 'moveAll', COPY: 'copy', + COPY_ALL: 'copyAll', COLUMN_MOVE: 'columnMove', COLUMN_COPY: 'columnCopy', ROW_MOVE: 'rowMove', @@ -29,7 +31,7 @@ export default function PanelEdit(props) { const [direction, setDirection] = useState('up') const { getMessage } = useMessage() const canvas = useRecoilValue(canvasState) - const { moduleMove, moduleCopy, moduleMultiMove, moduleMultiCopy } = useModule() + const { moduleMove, moduleCopy, moduleMultiMove, moduleMultiCopy, moduleMoveAll, moduleCopyAll } = useModule() useEffect(() => { if (canvas) { @@ -44,9 +46,15 @@ export default function PanelEdit(props) { case PANEL_EDIT_TYPE.MOVE: moduleMove(length, direction) break + case PANEL_EDIT_TYPE.MOVE_ALL: + moduleMoveAll(length, direction) + break case PANEL_EDIT_TYPE.COPY: moduleCopy(length, direction) break + case PANEL_EDIT_TYPE.COPY_ALL: + moduleCopyAll(length, direction) + break case PANEL_EDIT_TYPE.COLUMN_MOVE: moduleMultiMove('column', length, direction) break diff --git a/src/hooks/module/useModule.js b/src/hooks/module/useModule.js index 34f3f7bd..a4f50cbe 100644 --- a/src/hooks/module/useModule.js +++ b/src/hooks/module/useModule.js @@ -26,7 +26,8 @@ export const MODULE_INSERT_TYPE = { } export const MODULE_ALIGN_TYPE = { - TOP: 'top', + VERTICAL: 'vertical', + HORIZONTAL: 'horizontal', } export function useModule() { @@ -83,6 +84,162 @@ export function useModule() { } } } + 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 isWarning = false + + modules.forEach((module) => { + const { top, left } = getPosotion(module, direction, length, false) + module.originPos = { + top: module.top, + left: module.left, + fill: module.fill, + } + + module.set({ top, left }) + module.setCoords() + canvas.renderAll() + + if (otherModules.length > 0) { + if (isOverlapOtherModules(module, otherModules) || isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) { + isWarning = true + module.set({ fill: 'red' }) + } + } + }) + + canvas.renderAll() + if (isWarning) { + swalFire({ + title: getMessage('can.not.move.module'), + icon: 'error', + type: 'alert', + confirmFn: () => { + modules.forEach((module) => { + module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill }) + module.setCoords() + }) + canvas.renderAll() + }, + }) + } + } + + const moduleMoveAll = (length, direction) => { + const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] + const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE) + const objects = getObjects() + + let isWarning = false + + modules.forEach((module) => { + const { top, left } = getPosotion(module, direction, length, false) + module.originPos = { + top: module.top, + left: module.left, + fill: module.fill, + } + + module.set({ top, left }) + module.setCoords() + canvas.renderAll() + + if (isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) { + isWarning = true + module.set({ fill: 'red' }) + } + }) + + canvas.renderAll() + if (isWarning) { + swalFire({ + title: getMessage('can.not.move.module'), + icon: 'error', + type: 'alert', + confirmFn: () => { + modules.forEach((module) => { + module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill }) + module.setCoords() + }) + canvas.renderAll() + }, + }) + } + } + + const moduleCopyAll = (length, direction) => { + const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] + const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE) + const objects = getObjects() + const copyModules = [] + let copyModule = null + let isWarning = false + let moduleLength = 0 + if (['up', 'down'].includes(direction)) { + modules.sort((a, b) => a.top - b.top) + moduleLength = Number(modules[modules.length - 1].top) + Number(modules[modules.length - 1].height) - Number(modules[0].top) + } else if (['left', 'right'].includes(direction)) { + modules.sort((a, b) => a.left - b.left) + moduleLength = Number(modules[modules.length - 1].left) + Number(modules[modules.length - 1].width) - Number(modules[0].left) + } + + modules.forEach((module) => { + const { top, left } = getPosotion(module, direction, Number(length) + Number(moduleLength), false) + module.clone((obj) => { + obj.set({ + parentId: module.parentId, + initOptions: module.initOptions, + direction: module.direction, + arrow: module.arrow, + name: module.name, + type: module.type, + length: module.length, + points: module.points, + surfaceId: module.surfaceId, + left, + top, + id: uuidv4(), + }) + copyModule = obj + canvas.add(obj) + copyModules.push(obj) + obj.setCoords() + }) + if (isOverlapObjects(copyModule, objects) || isOutsideSurface(copyModule, moduleSetupSurface)) { + isWarning = true + copyModule.set({ fill: 'red' }) + } + canvas.renderAll() + }) + + if (isWarning) { + swalFire({ + title: getMessage('can.not.copy.module'), + icon: 'error', + type: 'alert', + confirmFn: () => { + canvas.remove(...copyModules) + canvas.renderAll() + }, + }) + } + } const moduleCopy = (length, direction) => { if (canvas.getActiveObjects().length === 0) return @@ -144,63 +301,6 @@ export function useModule() { } } - 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 isWarning = false - - modules.forEach((module) => { - const { top, left } = getPosotion(module, direction, length, false) - module.originPos = { - top: module.top, - left: module.left, - fill: module.fill, - } - - module.set({ top, left }) - module.setCoords() - canvas.renderAll() - - if (otherModules.length > 0) { - if (isOverlapOtherModules(module, otherModules) || isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) { - isWarning = true - module.set({ fill: 'red' }) - } - } - }) - - canvas.renderAll() - if (isWarning) { - swalFire({ - title: getMessage('can.not.move.module'), - icon: 'error', - type: 'alert', - confirmFn: () => { - modules.forEach((module) => { - module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill }) - module.setCoords() - }) - canvas.renderAll() - }, - }) - } - } - const moduleMultiCopy = (type, length, direction) => { if (canvas.getActiveObjects().length === 0) return if (canvas.getActiveObjects().length > 1) { @@ -694,7 +794,64 @@ export function useModule() { } } - const alignModule = (type) => {} + const alignModule = (type) => { + const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] + const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE) + const objects = getObjects() + const top = Math.min(...modules.map((module) => module.top)) + const left = Math.min(...modules.map((module) => module.left)) + const moduleSurfacePos = { + top: Math.min(...moduleSetupSurface.points.map((point) => point.y)), + left: Math.min(...moduleSetupSurface.points.map((point) => point.x)), + } + const [height, width] = [bottom - top, right - left] + const verticalCenterLength = moduleSurfacePos.top + moduleSetupSurface.height / 2 - (top + height / 2) + const horizontalCenterLength = moduleSurfacePos.left + moduleSetupSurface.width / 2 - (left + width / 2) + let isWarning = false + + canvas.discardActiveObject() + modules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + fill: module.fill, + } + if (type === MODULE_ALIGN_TYPE.VERTICAL) { + module.set({ top: module.top + verticalCenterLength }) + } else if (type === MODULE_ALIGN_TYPE.HORIZONTAL) { + module.set({ left: module.left + horizontalCenterLength }) + } + + canvas.renderAll() + module.setCoords() + if (isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) { + isWarning = true + module.set({ fill: 'red' }) + } + }) + canvas.renderAll() + if (isWarning) { + swalFire({ + title: getMessage('can.not.align.module'), + icon: 'error', + type: 'alert', + confirmFn: () => { + modules.forEach((module) => { + module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill }) + module.setCoords() + }) + canvas.renderAll() + }, + }) + } + } + + const modulesRemove = () => { + const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] + const modules = canvas.getObjects().filter((obj) => obj.surfaceId === activeModule.surfaceId && obj.name === POLYGON_TYPE.MODULE) + canvas.remove(...modules) + canvas.renderAll() + } const isOverlapOtherModules = (module, otherModules) => { return otherModules.some( @@ -765,11 +922,15 @@ export function useModule() { return { moduleMove, moduleMultiMove, + moduleMoveAll, moduleCopy, moduleMultiCopy, + moduleCopyAll, moduleColumnRemove, moduleRowRemove, moduleColumnInsert, muduleRowInsert, + modulesRemove, + alignModule, } } diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index 02896cb3..837c489a 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -1,7 +1,7 @@ import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import { canvasState, currentMenuState, currentObjectState } from '@/store/canvasAtom' import { useEffect, useState } from 'react' -import { MENU } from '@/common/common' +import { MENU, POLYGON_TYPE } from '@/common/common' import AuxiliarySize from '@/components/floor-plan/modal/auxiliary/AuxiliarySize' import { usePopup } from '@/hooks/usePopup' import { v4 as uuidv4 } from 'uuid' @@ -40,6 +40,7 @@ import { useCanvasSetting } from './option/useCanvasSetting' import { useGrid } from './common/useGrid' import { useAdsorptionPoint } from './useAdsorptionPoint' import { useRoofFn } from '@/hooks/common/useRoofFn' +import { MODULE_ALIGN_TYPE, useModule } from './module/useModule' export function useContextMenu() { const canvas = useRecoilValue(canvasState) @@ -66,6 +67,7 @@ export function useContextMenu() { const commonTextFont = useRecoilValue(fontSelector('commonText')) const { settingsData, setSettingsDataSave } = useCanvasSetting() const { swalFire } = useSwal() + const { alignModule } = useModule() const { removeRoofMaterial, removeAllRoofMaterial } = useRoofFn() const currentMenuSetting = () => { @@ -691,36 +693,38 @@ export function useContextMenu() { ]) break case 'moduleSetupSurface': - case 'dimensionLineText': + case 'roof': setContextMenu([ [ { id: 'moduleVerticalCenterAlign', name: getMessage('contextmenu.module.vertical.align'), + fn: () => alignModule(MODULE_ALIGN_TYPE.VERTICAL), }, { id: 'moduleHorizonCenterAlign', name: getMessage('contextmenu.module.horizon.align'), - }, - { - id: 'moduleLeftAlign', - name: getMessage('contextmenu.module.left.align'), - }, - { - id: 'moduleRightAlign', - name: getMessage('contextmenu.module.right.align'), - }, - { - id: 'moduleUpAlign', - name: getMessage('contextmenu.module.up.align'), - }, - { - id: 'moduleDownAlign', - name: getMessage('contextmenu.module.down.align'), + fn: () => alignModule(MODULE_ALIGN_TYPE.HORIZONTAL), }, { id: 'moduleRemove', name: getMessage('contextmenu.module.remove'), + fn: () => { + const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] + const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE) + canvas.remove(...modules) + canvas.renderAll() + }, + }, + { + id: 'moduleMove', + name: getMessage('contextmenu.module.move'), + component: , + }, + { + id: 'moduleCopy', + name: getMessage('contextmenu.module.copy'), + component: , }, { id: 'moduleCircuitNumberEdit',