This commit is contained in:
yoosangwook 2024-12-27 18:36:55 +09:00
commit ebe0608f76
6 changed files with 735 additions and 94 deletions

View File

@ -9,15 +9,27 @@ 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 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')
const { getMessage } = useMessage()
const canvas = useRecoilValue(canvasState)
const { moduleMove, moduleCopy, moduleMultiMove, moduleMultiCopy } = useModule()
useEffect(() => {
if (canvas) {
@ -28,7 +40,20 @@ export default function PanelEdit(props) {
//
const handleApply = () => {
contextModuleMove(length, direction)
// const activeModuleIds = canvas.getActiveObjects().map((obj) => obj.id)
if (type === PANEL_EDIT_TYPE.MOVE) {
moduleMove(length, direction)
} else if (type === PANEL_EDIT_TYPE.COPY) {
moduleCopy(length, direction)
} else if (type === PANEL_EDIT_TYPE.COLUMN_MOVE) {
moduleMultiMove('column', length, direction)
} else if (type === PANEL_EDIT_TYPE.COLUMN_COPY) {
moduleMultiCopy('column', length, direction)
} else if (type === PANEL_EDIT_TYPE.ROW_MOVE) {
moduleMultiMove('row', length, direction)
} else if (type === PANEL_EDIT_TYPE.ROW_COPY) {
moduleMultiCopy('row', length, direction)
}
closePopup(id)
}

View File

@ -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) {
<div className="additional-radio-wrap">
{types.map((type, index) => {
return (
<div className="d-check-radio pop">
<div className="d-check-radio pop" key={index}>
<input
type="radio"
name="radio01"
id={`ra0${index + 1}`}
onClick={(e) => 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) {
})}
</div>
<div className="additional-img-wrap">
{selectedType === 1 && (
{selectedType === MODULE_REMOVE_TYPE.LEFT && (
<Image
src="/static/images/canvas/additional_del01.svg"
alt="react"
@ -63,7 +66,7 @@ export default function ColumnRemove(props) {
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === 2 && (
{selectedType === MODULE_REMOVE_TYPE.RIGHT && (
<Image
src="/static/images/canvas/additional_del02.svg"
alt="react"
@ -72,7 +75,7 @@ export default function ColumnRemove(props) {
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === 3 && (
{selectedType === MODULE_REMOVE_TYPE.HORIZONTAL_SIDE && (
<Image
src="/static/images/canvas/additional_del03.svg"
alt="react"
@ -81,7 +84,7 @@ export default function ColumnRemove(props) {
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === 4 && (
{selectedType === MODULE_REMOVE_TYPE.NONE && (
<Image
src="/static/images/canvas/additional_del04.svg"
alt="react"

View File

@ -5,21 +5,24 @@ import { useRecoilValue } from 'recoil'
import { contextPopupPositionState } from '@/store/popupAtom'
import { usePopup } from '@/hooks/usePopup'
import { useMessage } from '@/hooks/useMessage'
import { MODULE_REMOVE_TYPE, useModule } from '@/hooks/module/useModule'
export default function RowRemove(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.TOP)
const { getMessage } = useMessage()
const { moduleRowRemove } = useModule()
const types = [
{ name: getMessage('modal.row.remove.type.up'), value: 1 },
{ name: getMessage('modal.row.remove.type.down'), value: 2 },
{ name: getMessage('modal.row.remove.type.side'), value: 3 },
{ name: getMessage('modal.row.remove.type.none'), value: 4 },
{ name: getMessage('modal.row.remove.type.up'), value: MODULE_REMOVE_TYPE.TOP },
{ name: getMessage('modal.row.remove.type.down'), value: MODULE_REMOVE_TYPE.BOTTOM },
{ name: getMessage('modal.row.remove.type.side'), value: MODULE_REMOVE_TYPE.VERTICAL_SIDE },
{ name: getMessage('modal.row.remove.type.none'), value: MODULE_REMOVE_TYPE.NONE },
]
const handleApply = () => {
if (apply) apply()
// if (apply) apply()
moduleRowRemove(selectedType)
closePopup(id)
}
@ -39,22 +42,22 @@ export default function RowRemove(props) {
<div className="additional-radio-wrap">
{types.map((type, index) => {
return (
<div className="d-check-radio pop">
<div className="d-check-radio pop" key={index}>
<input
type="radio"
name="radio01"
id={`ra0${index + 1}`}
onClick={() => setSelectedType(Number(e.target.value))}
onClick={(e) => setSelectedType(e.target.value)}
value={type.value}
checked={selectedType === type.value}
/>
<label htmlFor="ra01">{getMessage(type.name)}</label>
<label htmlFor={`ra0${index + 1}`}>{type.name}</label>
</div>
)
})}
</div>
<div className="additional-img-wrap">
{selectedType === 1 && (
{selectedType === MODULE_REMOVE_TYPE.TOP && (
<Image
src="/static/images/canvas/additional_bundle-del01.svg"
alt="react"
@ -63,7 +66,7 @@ export default function RowRemove(props) {
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === 2 && (
{selectedType === MODULE_REMOVE_TYPE.BOTTOM && (
<Image
src="/static/images/canvas/additional_bundle-del02.svg"
alt="react"
@ -72,7 +75,7 @@ export default function RowRemove(props) {
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === 3 && (
{selectedType === MODULE_REMOVE_TYPE.VERTICAL_SIDE && (
<Image
src="/static/images/canvas/additional_bundle-del03.svg"
alt="react"
@ -81,7 +84,7 @@ export default function RowRemove(props) {
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === 4 && (
{selectedType === MODULE_REMOVE_TYPE.NONE && (
<Image
src="/static/images/canvas/additional_bundle-del04.svg"
alt="react"

View File

@ -0,0 +1,605 @@
import { BATCH_TYPE, POLYGON_TYPE } from '@/common/common'
import { canvasState } from '@/store/canvasAtom'
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',
RIGHT: 'right',
HORIZONTAL_SIDE: 'horizontalSide',
TOP: 'top',
BOTTOM: 'bottom',
VERTICAL_SIDE: 'verticalSide',
NONE: 'none',
}
export function useModule() {
const canvas = useRecoilValue(canvasState)
const { swalFire } = useSwal()
const { checkModuleDisjointObjects } = useModuleBasicSetting()
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 = []
const isOverlapObjects = []
const objects = getObjects()
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)
isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects))
})
const isNotOverlap = isOverlapArray.some((isOverlap) => isOverlap) // true면 겹침
const isNotOutSurface = isInSurfaceArray.every((isOutSurface) => isOutSurface) //false면 밖으로 나감
//안겹치고 안나갔으면 이동시킨다 아니면 원래 위치로 돌려놓는다
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()
})
},
})
}
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 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)
const moduleOptions = { ...module, left, top, id: uuidv4() }
const rect = new QPolygon(module.points, moduleOptions)
canvas.add(rect)
rect.setCoords()
canvas.renderAll()
isOverlapOtherModules.push(
otherModules.some(
(otherModule) =>
turf.booleanOverlap(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)) ||
turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)),
),
)
isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(rect, true), objects))
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 ? '겹치는 모듈이 있습니다.' : isOutsideSurface ? '모듈이 오브젝트와 겹칩니다.' : '영역 밖',
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()
console.log('🚀 ~ moduleMultiMove ~ objects:', objects)
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(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects))
}
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)
? '겹치는 모듈이 있습니다.'
: isOverlapObjects.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, false)
const moduleOptions = { ...module, left, top, id: uuidv4() }
const rect = new QPolygon(module.getCurrentPoints(), 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(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects))
}
isOutsideSurface.push(
!turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(rect, true)) ||
!turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(moduleSetupSurface, true)),
)
})
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: () => {
canvas.remove(...copyRects)
canvas.renderAll()
},
})
} else {
canvas.renderAll()
}
}
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()
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] = [[], [], []]
canvas.discardActiveObject()
canvas.remove(...columnModules)
canvas.renderAll()
if (type === MODULE_REMOVE_TYPE.LEFT) {
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(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), 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(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), 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(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), 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(...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(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), 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(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), 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(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), 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)
}
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(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))
}
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,
moduleCopy,
moduleMultiCopy,
moduleColumnRemove,
moduleRowRemove,
}
}

View File

@ -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,
}
}

View File

@ -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: <PanelEdit id={popupId} type={'move'} />,
component: <PanelEdit id={popupId} type={PANEL_EDIT_TYPE.MOVE} />,
},
{
id: 'copy',
name: getMessage('contextmenu.copy'),
component: <PanelEdit id={popupId} type={'copy'} />,
component: <PanelEdit id={popupId} type={PANEL_EDIT_TYPE.COPY} />,
},
],
[
{
id: 'columnMove',
name: getMessage('contextmenu.column.move'),
component: <PanelEdit id={popupId} type={'columnMove'} />,
component: <PanelEdit id={popupId} type={PANEL_EDIT_TYPE.COLUMN_MOVE} />,
},
{
id: 'columnCopy',
name: getMessage('contextmenu.column.copy'),
component: <PanelEdit id={popupId} type={'columnCopy'} />,
component: <PanelEdit id={popupId} type={PANEL_EDIT_TYPE.COLUMN_COPY} />,
},
{
id: 'columnRemove',
@ -643,12 +643,12 @@ export function useContextMenu() {
{
id: 'rowMove',
name: getMessage('contextmenu.row.move'),
component: <PanelEdit id={popupId} type={'rowMove'} />,
component: <PanelEdit id={popupId} type={PANEL_EDIT_TYPE.ROW_MOVE} />,
},
{
id: 'rowCopy',
name: getMessage('contextmenu.row.copy'),
component: <PanelEdit id={popupId} type={'rowCopy'} />,
component: <PanelEdit id={popupId} type={PANEL_EDIT_TYPE.ROW_COPY} />,
},
{
id: 'rowRemove',