dev #930
@ -16,7 +16,7 @@ import { useSwal } from '@/hooks/useSwal'
|
||||
export default function SizeSetting(props) {
|
||||
const contextPopupPosition = useRecoilValue(contextPopupPositionState)
|
||||
const [settingTarget, setSettingTarget] = useState(props.side || 1)
|
||||
const { id, pos = contextPopupPosition, target } = props
|
||||
const { id, pos = contextPopupPosition, target, initialPlacement = false } = props
|
||||
const { getMessage } = useMessage()
|
||||
const { closePopup } = usePopup()
|
||||
const { resizeObjectBatch } = useObjectBatch({})
|
||||
@ -58,7 +58,7 @@ export default function SizeSetting(props) {
|
||||
}
|
||||
|
||||
if (target.name === BATCH_TYPE.OPENING || target.name === BATCH_TYPE.SHADOW) {
|
||||
resizeObjectBatch(settingTarget, target, width, height, id)
|
||||
resizeObjectBatch(settingTarget, target, width, height, id, initialPlacement)
|
||||
} else if (target.name === POLYGON_TYPE.ROOF) {
|
||||
resizeSurfaceShapeBatch(settingTarget, target, width, height, id)
|
||||
}
|
||||
|
||||
@ -209,7 +209,9 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
|
||||
initEvent()
|
||||
|
||||
closeAll()
|
||||
addPopup(popupId, 1, <SizeSetting id={popupId} target={rect} />)
|
||||
// 초기 배치 흐름에서 연 사이즈 설정: 배치 시작(applyOpeningAndShadow)이 이미 "오브젝트 없음" 스냅샷을
|
||||
// 찍어뒀으므로, 이 사이즈 확정은 중복 스냅샷을 만들지 않게 한다(undo 한 번에 제거되도록).
|
||||
addPopup(popupId, 1, <SizeSetting id={popupId} target={rect} initialPlacement />)
|
||||
}
|
||||
})
|
||||
} else if (selectedType === INPUT_TYPE.DIMENSION) {
|
||||
@ -1305,8 +1307,10 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
|
||||
return { leftPoints, rightPoints, groupPoints }
|
||||
}
|
||||
|
||||
const resizeObjectBatch = (side, target, width, height, popupId) => {
|
||||
saveSnapshot()
|
||||
const resizeObjectBatch = (side, target, width, height, popupId, skipSnapshot = false) => {
|
||||
// 초기 배치(applyOpeningAndShadow)에서 열린 사이즈 설정이면 배치 시작 스냅샷과 중복되므로 건너뛴다.
|
||||
// 컨텍스트 메뉴 "사이즈 수정"으로 기존 오브젝트를 수정할 땐 skipSnapshot=false 라 별개 undo 로 남는다.
|
||||
if (!skipSnapshot) saveSnapshot()
|
||||
const objectWidth = target.width
|
||||
const objectHeight = target.height
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ import { fabric } from 'fabric'
|
||||
import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint'
|
||||
import { useSwal } from '@/hooks/useSwal'
|
||||
import { usePopup } from '@/hooks/usePopup'
|
||||
import { useUndoRedo } from '@/hooks/useUndoRedo'
|
||||
import { calculateAngle, isSamePoint } from '@/util/qpolygon-utils'
|
||||
import { POLYGON_TYPE } from '@/common/common'
|
||||
import { useMessage } from '../useMessage'
|
||||
@ -36,6 +37,7 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
|
||||
const { getAdsorptionPoints } = useAdsorptionPoint()
|
||||
const { closePopup } = usePopup()
|
||||
const { getMessage } = useMessage()
|
||||
const { saveSnapshot, setDrawing, popLastSnapshot } = useUndoRedo()
|
||||
|
||||
const adsorptionRange = useRecoilValue(adsorptionRangeState)
|
||||
|
||||
@ -44,6 +46,7 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
|
||||
const mousePointerArr = useRef([])
|
||||
const roofAdsorptionPoints = useRef([])
|
||||
const lineHistory = useRef([])
|
||||
const isFix = useRef(false)
|
||||
|
||||
const length1Ref = useRef(0)
|
||||
const length2Ref = useRef(0)
|
||||
@ -117,6 +120,24 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
|
||||
}
|
||||
}, [])
|
||||
|
||||
// 보조선 그리기 시작 시 스냅샷 저장 (undo 하면 보조선 적용 전 상태로 복원).
|
||||
// 그리기 진행 중에는 undo/redo/snapshot 을 차단하므로 force 로 저장한다.
|
||||
// 편집 모달(AuxiliaryEdit) 은 id 없이 hook 을 호출하므로 제외한다.
|
||||
useEffect(() => {
|
||||
if (!id) return
|
||||
const roofs = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||
if (!roofs || roofs.length === 0) return
|
||||
setDrawing(true)
|
||||
saveSnapshot(null, { force: true })
|
||||
return () => {
|
||||
setDrawing(false)
|
||||
// 확정(완료)하지 않고 닫은 경우 스냅샷 제거
|
||||
if (!isFix.current) {
|
||||
popLastSnapshot()
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (type === null) {
|
||||
return
|
||||
@ -918,6 +939,9 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
|
||||
return
|
||||
}
|
||||
|
||||
// 완료 확정 → 마운트 시 저장한 "보조선 적용 전" 스냅샷을 유지 (언마운트 cleanup 에서 pop 하지 않음)
|
||||
isFix.current = true
|
||||
|
||||
// cutAuxiliary()
|
||||
|
||||
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||
@ -978,6 +1002,7 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
|
||||
roofBase.innerLines = lineHistory.current.length !== 0 ? [...roofInnerLines] : roofBase.innerLines
|
||||
canvas.renderAll()
|
||||
})
|
||||
|
||||
closePopup(id)
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, currentObjectState, pitchTextSelector } from '@/store/canvasAtom'
|
||||
import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, currentMenuState, currentObjectState, pitchTextSelector } from '@/store/canvasAtom'
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil'
|
||||
import { currentMenuState } from '@/store/canvasAtom'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useLine } from '@/hooks/useLine'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
@ -38,6 +37,7 @@ export function useRoofShapePassivitySetting(id) {
|
||||
const history = useRef([])
|
||||
const [type, setType] = useState(TYPES.EAVES)
|
||||
const isFix = useRef(false)
|
||||
const isConverted = useRef(false)
|
||||
const initLines = useRef([])
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
@ -52,7 +52,7 @@ export function useRoofShapePassivitySetting(id) {
|
||||
useEffect(() => {
|
||||
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||
if (!canvas.outerLineFix || outerLines.length === 0) {
|
||||
swalFire({ text: getMessage('wall.line.not.found'),icon: 'warning' })
|
||||
swalFire({ text: getMessage('wall.line.not.found'), icon: 'warning' })
|
||||
closePopup(id)
|
||||
//return
|
||||
}
|
||||
@ -176,7 +176,6 @@ export function useRoofShapePassivitySetting(id) {
|
||||
}
|
||||
}
|
||||
|
||||
saveSnapshot()
|
||||
currentLineRef.current.set({
|
||||
attributes: { ...attributes, isFixed: true },
|
||||
})
|
||||
@ -202,7 +201,13 @@ export function useRoofShapePassivitySetting(id) {
|
||||
}
|
||||
|
||||
const handleSave = () => {
|
||||
saveSnapshot(null, { force: true })
|
||||
// 모든 외곽선이 처마/케라바/편류 중 하나로 설정되었는지 검증 → 미설정 라인이 있으면 완료 차단
|
||||
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||
const isAllSet = lines.length > 0 && lines.every((line) => !!line.attributes?.type)
|
||||
if (!isAllSet) {
|
||||
swalFire({ text: getMessage('modal.canvas.setting.roofline.properties.setting.not.setting'), icon: 'warning' })
|
||||
return
|
||||
}
|
||||
isFix.current = true
|
||||
handleLineToPolygon()
|
||||
// 수동설정 완료 → 지붕면 할당 메뉴로 전환 (undo 가드 해제)
|
||||
@ -211,6 +216,10 @@ export function useRoofShapePassivitySetting(id) {
|
||||
}
|
||||
|
||||
const handleLineToPolygon = () => {
|
||||
// 완료(handleSave) 후 closePopup → 언마운트 cleanup 에서 중복 호출되는 것을 방지 (스냅샷/지붕 중복 생성 차단)
|
||||
if (isConverted.current) return
|
||||
isConverted.current = true
|
||||
|
||||
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||
const exceptObjs = canvas.getObjects().filter((obj) => obj.name !== 'outerLine' && obj.parent?.name !== 'outerLine')
|
||||
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||
@ -259,6 +268,8 @@ export function useRoofShapePassivitySetting(id) {
|
||||
if (isFix.current) {
|
||||
// 완료 한 경우에는 지붕까지 그려줌
|
||||
addPitchTextsByOuterLines()
|
||||
// 지붕 그리기 직전(라인 세팅 완료) 상태를 스냅샷 → undo 시 지붕이 그려지기 전 화면으로 복귀
|
||||
saveSnapshot(null, { force: true })
|
||||
const roof = drawRoofPolygon(wall)
|
||||
addLengthText(roof)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user