diff --git a/src/hooks/roofcover/useRoofShapePassivitySetting.js b/src/hooks/roofcover/useRoofShapePassivitySetting.js index e0223139..14c648f0 100644 --- a/src/hooks/roofcover/useRoofShapePassivitySetting.js +++ b/src/hooks/roofcover/useRoofShapePassivitySetting.js @@ -36,6 +36,7 @@ export function useRoofShapePassivitySetting(id) { const [type, setType] = useState(TYPES.EAVES) const isFix = useRef(false) const initLines = useRef([]) + const removedWalls = useRef([]) const [isLoading, setIsLoading] = useState(false) const { closePopup } = usePopup() @@ -60,6 +61,7 @@ export function useRoofShapePassivitySetting(id) { addCanvasMouseEventListener('mouse:down', mouseDown) const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) + removedWalls.current = wallLines.map((wall) => ({ wall, index: canvas.getObjects().indexOf(wall) })) canvas?.remove(...wallLines) const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') @@ -198,10 +200,32 @@ export function useRoofShapePassivitySetting(id) { } const handleLineToPolygon = () => { - 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') + if (!isFix.current) { + // 저장 없이 닫을 경우 진입 시점 스냅샷으로 롤백 — 캔버스를 진입 전 상태 그대로 되돌린다 + lines.forEach((line, idx) => { + const init = initLines.current[idx] + if (!init) { + return + } + init.visible ? showLine(line) : hideLine(line) + line.set({ stroke: init.stroke, strokeWidth: init.strokeWidth, selectable: init.selectable }) + line.attributes = init.attributes + }) + + // 진입 시 삭제했던 WALL 폴리곤 원본을 원래 z-순서 그대로 재삽입 + removedWalls.current.forEach(({ wall, index }) => { + canvas.insertAt(wall, index) + }) + removedWalls.current = [] + + canvas.renderAll() + return + } + + const exceptObjs = canvas.getObjects().filter((obj) => obj.name !== 'outerLine' && obj.parent?.name !== 'outerLine') + let checkedAllSetting = true lines.forEach((line) => { @@ -219,36 +243,27 @@ export function useRoofShapePassivitySetting(id) { canvas.remove(obj) }) + // 저장 시에는 자동 설정과 동일하게 외벽선을 타입별 색상으로 표시 lines.forEach((line) => { - hideLine(line) + let stroke + if (line.attributes?.type === LINE_TYPE.WALLLINE.EAVES || line.attributes?.type === LINE_TYPE.WALLLINE.HIPANDGABLE) { + stroke = '#45CD7D' + } else if (line.attributes?.type === LINE_TYPE.WALLLINE.GABLE || line.attributes?.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + stroke = '#3FBAE6' + } else { + stroke = '#000000' + } + line.set({ stroke, strokeWidth: 4, selectable: false, visible: true }) }) - let wall - - if (isFix.current) { - wall = addPolygonByLines(lines, { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' }) - } else { - // 그냥 닫을 경우 처리 - wall = addPolygonByLines([...initLines.current], { - name: POLYGON_TYPE.WALL, - fill: 'transparent', - stroke: 'black', - }) - lines.forEach((line, idx) => { - line.attributes = initLines.current[idx].attributes - }) - } - + const wall = addPolygonByLines(lines, { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' }) wall.lines = [...lines] - // 기존 그려진 지붕이 없다면 - - if (isFix.current) { - // 완료 한 경우에는 지붕까지 그려줌 - addPitchTextsByOuterLines() - const roof = drawRoofPolygon(wall) - addLengthText(roof) - } + // 완료 한 경우에는 지붕까지 그려줌 + addPitchTextsByOuterLines() + const roof = drawRoofPolygon(wall) + addLengthText(roof) + lines.forEach((line) => line.bringToFront()) canvas.renderAll() } diff --git a/src/hooks/roofcover/useRoofShapeSetting.js b/src/hooks/roofcover/useRoofShapeSetting.js index f5c84f5b..58fec3df 100644 --- a/src/hooks/roofcover/useRoofShapeSetting.js +++ b/src/hooks/roofcover/useRoofShapeSetting.js @@ -52,6 +52,11 @@ export function useRoofShapeSetting(id) { const isFixRef = useRef(false) + // 저장 없이 닫을 때 롤백할 진입 시점 스냅샷 + const initLinesRef = useRef([]) + const removedWallsRef = useRef([]) + const pitchTextLineIdsRef = useRef(new Set()) + const pitchRef = useRef(null) const shedPitchRef = useRef(null) const jerkinHeadPitchRef = useRef(null) @@ -87,14 +92,46 @@ export function useRoofShapeSetting(id) { closePopup(id) return } - return () => { - if (!isFixRef.current) { - return - } + initLinesRef.current = outerLines.map((line) => ({ ...line })) + pitchTextLineIdsRef.current = new Set( + canvas + .getObjects() + .filter((obj) => obj.name === 'pitchText') + .map((obj) => obj.parentId), + ) + + return () => { const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') const pitchTexts = canvas.getObjects().filter((obj) => obj.name === 'pitchText') + if (!isFixRef.current) { + // 저장 없이 닫을 경우 진입 시점 스냅샷으로 롤백 — 캔버스를 진입 전 상태 그대로 되돌린다 + canvas.remove(...pitchTexts) + outerLines.forEach((line, idx) => { + const init = initLinesRef.current[idx] + if (!init) { + return + } + init.visible ? showLine(line) : hideLine(line) + line.set({ stroke: init.stroke, strokeWidth: init.strokeWidth, selectable: init.selectable }) + line.attributes = init.attributes + if (pitchTextLineIdsRef.current.has(line.id)) { + addPitchText(line) + } + }) + + // 변별로 설정 진입 시 삭제했던 WALL 폴리곤 원본을 원래 z-순서 그대로 재삽입 + removedWallsRef.current.forEach(({ wall, index }) => { + canvas.insertAt(wall, index) + }) + removedWallsRef.current = [] + + canvas.discardActiveObject() + canvas.renderAll() + return + } + canvas.remove(...pitchTexts) outerLines.forEach((line) => { let stroke, strokeWidth @@ -113,6 +150,8 @@ export function useRoofShapeSetting(id) { line.set({ stroke, strokeWidth, + selectable: false, + visible: true, }) addPitchText(line) @@ -144,10 +183,15 @@ export function useRoofShapeSetting(id) { useEffect(() => { if (shapeNum === 4) { - canvas?.remove(canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.WALL)) + const wall = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.WALL) + if (wall && removedWallsRef.current.length === 0) { + removedWallsRef.current = [{ wall, index: canvas.getObjects().indexOf(wall) }] + } + canvas?.remove(wall) const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') outerLines.forEach((line) => { showLine(line) + line.set({ selectable: true }) line.bringToFront() })