From 13292d4c5093d5de247ac365a7ab75cdcce7f69b Mon Sep 17 00:00:00 2001 From: ysCha Date: Fri, 30 Jan 2026 14:15:50 +0900 Subject: [PATCH 1/6] =?UTF-8?q?[1444]=EC=9C=A1=EC=A7=80=EB=B4=89=20?= =?UTF-8?q?=EB=A9=94=EB=89=B4=20=EC=9E=84=EC=8B=9C=EC=82=AD=EC=A0=9C(?= =?UTF-8?q?=EC=9A=B4=EC=98=81=EB=A7=8C)?= 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, 1 insertion(+), 1 deletion(-) diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx index 95442b8a..4ec45dd5 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx @@ -63,7 +63,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla const roofSizeSetArray = [ { id: 'ra01', name: 'roofSizeSet', value: '1', message: 'modal.placement.initial.setting.size.roof' }, { id: 'ra02', name: 'roofSizeSet', value: '2', message: 'modal.placement.initial.setting.size.actual' }, - // { id: 'ra03', name: 'roofSizeSet', value: '3', message: 'modal.placement.initial.setting.size.none.pitch' }, + { id: 'ra03', name: 'roofSizeSet', value: '3', message: 'modal.placement.initial.setting.size.none.pitch' }, ] /** From d643ffe2ea05d2fd7fa76a12890951044d23d134 Mon Sep 17 00:00:00 2001 From: ysCha Date: Fri, 30 Jan 2026 14:34:57 +0900 Subject: [PATCH 2/6] =?UTF-8?q?[1444]=EC=9C=A1=EC=A7=80=EB=B4=89=20TypeErr?= =?UTF-8?q?or:=20Cannot=20destructure=20property=20'rackYn'=20of=20'trestl?= =?UTF-8?q?eDetail'=20as=20it=20is=20null.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../circuitTrestle/CircuitTrestleSetting.jsx | 3 +++ src/hooks/module/useModule.js | 4 ++-- src/hooks/module/useModuleBasicSetting.js | 19 ++++++++++++++++++- src/hooks/module/useTrestle.js | 8 ++++++-- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx index 4c4ea028..02e9d171 100644 --- a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx @@ -124,6 +124,9 @@ export default function CircuitTrestleSetting({ id }) { */ const validateModuleSizeForRack = (surface) => { const { modules, direction, trestleDetail } = surface + if (!trestleDetail) { + return true // 상세 정보 없음 + } const { rackYn, moduleIntvlHor, moduleIntvlVer } = trestleDetail if (rackYn === 'N' || !modules || modules.length < 2) { diff --git a/src/hooks/module/useModule.js b/src/hooks/module/useModule.js index 45b3b50f..8e59a1e7 100644 --- a/src/hooks/module/useModule.js +++ b/src/hooks/module/useModule.js @@ -749,7 +749,7 @@ export function useModule() { const copyModules = [] const moduleSetupSurface = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId) let isWarning = false - const { moduleIntvlHor, moduleIntvlVer } = moduleSetupSurface.trestleDetail + const { moduleIntvlHor = 0, moduleIntvlVer = 0 } = moduleSetupSurface.trestleDetail || {} canvas.discardActiveObject() targetModules.forEach((module) => { const { top, left } = getPosotion(module, type, moduleIntvlHor, true) @@ -859,7 +859,7 @@ export function useModule() { const copyModules = [] const moduleSetupSurface = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId) let isWarning = false - const { moduleIntvlHor, moduleIntvlVer } = moduleSetupSurface.trestleDetail + const { moduleIntvlHor = 0, moduleIntvlVer = 0 } = moduleSetupSurface.trestleDetail || {} canvas.discardActiveObject() targetModules.forEach((module) => { const { top, left } = getPosotion(module, type, moduleIntvlVer, true) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 45fd8a53..5ddf69d0 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -338,10 +338,27 @@ export function useModuleBasicSetting(tabNum) { }) let isNorth = false + const defaultTrestleDetail = { + rackYn: 'N', + moduleIntvlHor: +roofSizeSet === 3 ? 300 : 0, + moduleIntvlVer: +roofSizeSet === 3 ? 100 : 0, + rack: null, + rackQty: 0, + rackIntvlPct: 0, + cvrPlvrYn: 'N', + lessSupFitIntvlPct: 0, + lessSupFitQty: 0, + } const isExistSurface = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.parentId === roof.id) + const normalizedTrestleDetail = trestleDetail + ? { ...defaultTrestleDetail, ...trestleDetail } + : isExistSurface?.trestleDetail + ? { ...defaultTrestleDetail, ...isExistSurface.trestleDetail } + : defaultTrestleDetail if (isExistSurface) { + isExistSurface.set({ trestleDetail: normalizedTrestleDetail }) if (canvasSetting.roofSizeSet != '3') { //북면이 있지만 if (roof.directionText && roof.directionText.indexOf('北') > -1) { @@ -424,7 +441,7 @@ export function useModuleBasicSetting(tabNum) { originY: 'center', modules: [], roofMaterial: roof.roofMaterial, - trestleDetail: trestleDetail, + trestleDetail: normalizedTrestleDetail, isNorth: isNorth, perPixelTargetFind: true, isSaleStoreNorthFlg: moduleSelectionData.common.saleStoreNorthFlg == '1' ? true : false, //북면설치가능점 여부 diff --git a/src/hooks/module/useTrestle.js b/src/hooks/module/useTrestle.js index 88980cad..e4ee52a8 100644 --- a/src/hooks/module/useTrestle.js +++ b/src/hooks/module/useTrestle.js @@ -65,6 +65,10 @@ export const useTrestle = () => { if (+roofSizeSet === 3) { return } + const trestleDetail = surface.trestleDetail + if (!trestleDetail) { + return + } const construction = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex).construction if (!construction) { return @@ -76,8 +80,8 @@ export const useTrestle = () => { let isSnowGuard = construction.setupSnowCover let cvrLmtRow = construction.cvrLmtRow const direction = parent.direction - const rack = surface.trestleDetail.rack - let { rackQty, rackIntvlPct, rackYn, cvrPlvrYn, lessSupFitIntvlPct, lessSupFitQty } = surface.trestleDetail + const rack = trestleDetail.rack + let { rackQty, rackIntvlPct, rackYn, cvrPlvrYn, lessSupFitIntvlPct, lessSupFitQty } = trestleDetail if (!rack && lessSupFitIntvlPct === 0 && lessSupFitQty === 0) { //25/02/06 가대없음의 경우 랙정보가 없음 From c9f0a70385a160a6e8be31d267a57dedae4956e1 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Fri, 30 Jan 2026 15:51:46 +0900 Subject: [PATCH 3/6] =?UTF-8?q?=EB=AA=A8=EB=93=88=20=EC=84=A4=EC=B9=98=20?= =?UTF-8?q?=EC=A0=9C=EB=8C=80=EB=A1=9C=20=EC=95=88=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=ED=98=84=EC=83=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/module/useModuleBasicSetting.js | 145 ++++++++++++++++------ 1 file changed, 109 insertions(+), 36 deletions(-) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 45fd8a53..ce7069ac 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -17,7 +17,7 @@ import { import { calculateVisibleModuleHeight, getDegreeByChon, polygonToTurfPolygon, rectToPolygon, toFixedWithoutRounding } from '@/util/canvas-util' import '@/util/fabric-extensions' // fabric 객체들에 getCurrentPoints 메서드 추가 import { basicSettingState, roofDisplaySelector } from '@/store/settingAtom' -import offsetPolygon, { calculateAngle, createLinesFromPolygon, cleanSelfIntersectingPolygon } from '@/util/qpolygon-utils' +import offsetPolygon, { calculateAngle, cleanSelfIntersectingPolygon, createLinesFromPolygon } from '@/util/qpolygon-utils' import { QPolygon } from '@/components/fabric/QPolygon' import { useEvent } from '@/hooks/useEvent' import { BATCH_TYPE, LINE_TYPE, MODULE_SETUP_TYPE, POLYGON_TYPE } from '@/common/common' @@ -2105,7 +2105,7 @@ export function useModuleBasicSetting(tabNum) { } //흐름 방향이 남쪽(아래) - const downFlowSetupModule = (maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) => { + const downFlowSetupModule = (maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer, symmetricWidthRef) => { let setupModule = [] const trestleDetailData = moduleSetupSurface.trestleDetail @@ -2184,6 +2184,11 @@ export function useModuleBasicSetting(tabNum) { calcAreaHeight = isNaN(calcAreaHeight) ? moduleSetupSurface.height : calcAreaHeight let calcModuleHeightCount = calcAreaHeight / (height + intvVer) + // 대칭 지붕을 위해 south의 calcAreaWidth 저장 (north에서 참조) + if (symmetricWidthRef && moduleIndex === 0) { + symmetricWidthRef.south = calcAreaWidth + } + if (type === MODULE_SETUP_TYPE.LAYOUT) { calcModuleWidthCount = layoutCol > calcModuleWidthCount ? calcModuleWidthCount : layoutCol calcModuleHeightCount = layoutRow @@ -2287,7 +2292,7 @@ export function useModuleBasicSetting(tabNum) { } } - const topFlowSetupModule = (maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) => { + const topFlowSetupModule = (maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer, symmetricWidthRef) => { let setupModule = [] const trestleDetailData = moduleSetupSurface.trestleDetail @@ -2366,9 +2371,22 @@ export function useModuleBasicSetting(tabNum) { //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음 const moduleArray = [] - let calcAreaWidth = flowLines.right.x1 - flowLines.left.x1 //오른쪽 x에서 왼쪽 x를 뺀 가운데를 찾는 로직 + // 북쪽: 남쪽과 동일한 방식으로 계산 (대칭을 위해) + let calcAreaWidth = Math.abs(flowLines.right.x1 - flowLines.left.x1) //오른쪽 x에서 왼쪽 x를 뺀 가운데를 찾는 로직 + + // 대칭 지붕: south의 calcAreaWidth가 있고 north의 값이 south보다 10% 이상 작으면 south 값 사용 + if (symmetricWidthRef?.south && calcAreaWidth < symmetricWidthRef.south * 0.9) { + // flowLines 좌표도 보정 (중심점 유지하면서 너비 확장) + const center = (flowLines.right.x1 + flowLines.left.x1) / 2 + const halfWidth = symmetricWidthRef.south / 2 + flowLines.left.x1 = center - halfWidth + flowLines.right.x1 = center + halfWidth + + calcAreaWidth = symmetricWidthRef.south + } + let calcModuleWidthCount = calcAreaWidth / (width + intvHor) //뺀 공간에서 모듈을 몇개를 넣을수 있는지 확인하는 로직 - let calcAreaHeight = flowLines.bottom.y1 - flowLines.top.y1 + let calcAreaHeight = Math.abs(flowLines.bottom.y1 - flowLines.top.y1) let calcModuleHeightCount = calcAreaHeight / (height + intvVer) //단수지정 자동이면 @@ -2469,7 +2487,7 @@ export function useModuleBasicSetting(tabNum) { //남, 북과 같은 로직으로 적용하려면 좌우는 열 -> 행 으로 그려야함 //변수명은 bottom 기준으로 작성하여 동일한 방향으로 진행한다 - const leftFlowSetupModule = (maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) => { + const leftFlowSetupModule = (maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer, symmetricWidthRef) => { let setupModule = [] const trestleDetailData = moduleSetupSurface.trestleDetail //가대 상세 데이터 @@ -2557,6 +2575,11 @@ export function useModuleBasicSetting(tabNum) { let calcAreaHeight = Math.abs(flowLines.right.x1 - flowLines.left.x1) let calcModuleHeightCount = calcAreaHeight / (width + intvVer) + // 대칭 지붕을 위해 west의 calcAreaWidth 저장 (east에서 참조) + if (symmetricWidthRef && moduleIndex === 0) { + symmetricWidthRef.west = calcAreaWidth + } + //단수지정 자동이면 if (type === MODULE_SETUP_TYPE.LAYOUT) { calcModuleWidthCount = layoutCol > calcModuleWidthCount ? calcModuleWidthCount : layoutCol @@ -2655,7 +2678,7 @@ export function useModuleBasicSetting(tabNum) { } } - const rightFlowSetupModule = (maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) => { + const rightFlowSetupModule = (maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer, symmetricWidthRef) => { let setupModule = [] const trestleDetailData = moduleSetupSurface.trestleDetail //가대 상세 데이터 @@ -2736,9 +2759,22 @@ export function useModuleBasicSetting(tabNum) { //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음 const moduleArray = [] - let calcAreaWidth = flowLines.bottom.y1 - flowLines.top.y1 //아래에서 y에서 위를 y를 뺀 가운데를 찾는 로직 + // 동쪽: 서쪽과 동일한 방식으로 계산 (대칭을 위해) + let calcAreaWidth = Math.abs(flowLines.bottom.y1 - flowLines.top.y1) //아래에서 y에서 위를 y를 뺀 가운데를 찾는 로직 + + // 대칭 지붕: west의 calcAreaWidth가 있고 east의 값이 west보다 10% 이상 작으면 west 값 사용 + if (symmetricWidthRef?.west && calcAreaWidth < symmetricWidthRef.west * 0.9) { + // flowLines 좌표도 보정 (중심점 유지하면서 높이 확장) + const center = (flowLines.bottom.y1 + flowLines.top.y1) / 2 + const halfHeight = symmetricWidthRef.west / 2 + flowLines.top.y1 = center - halfHeight + flowLines.bottom.y1 = center + halfHeight + + calcAreaWidth = symmetricWidthRef.west + } + let calcModuleWidthCount = calcAreaWidth / (height + intvHor) //뺀 공간에서 모듈을 몇개를 넣을수 있는지 확인하는 로직 - let calcAreaHeight = flowLines.right.x1 - flowLines.left.x1 + let calcAreaHeight = Math.abs(flowLines.right.x1 - flowLines.left.x1) let calcModuleHeightCount = calcAreaHeight / (width + intvVer) //단수지정 자동이면 @@ -2748,15 +2784,14 @@ export function useModuleBasicSetting(tabNum) { } let calcMaxModuleWidthCount = calcModuleWidthCount > moduleMaxCols ? moduleMaxCols : calcModuleWidthCount //최대 모듈 단수가 있기 때문에 최대 단수보다 카운트가 크면 최대 단수로 씀씀 - // let totalModuleWidthCount = isChidori ? Math.abs(calcMaxModuleWidthCount) : Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다 - let totalModuleWidthCount = Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다 + let totalModuleWidthCount = Math.floor(calcMaxModuleWidthCount) let calcStartPoint = flowLines.top.type === 'flat' ? (calcAreaWidth - totalModuleWidthCount * height) / 2 : 0 //반씩 나눠서 중앙에 맞춤 left 높이 기준으로 양변이 직선일때만 가운데 정렬 - let startPointX = flowLines.bottom.y2 - calcStartPoint //시작점을 만든다 + let startPointX = flowLines.bottom.y1 - calcStartPoint //시작점을 만든다 //근데 양변이 곡선이면 중앙에 맞추기 위해 아래와 위의 길이를 재서 모듈의 길이를 나눠서 들어갈수 있는 갯수가 동일하면 가운데로 정렬 시킨다 if (flowLines.top.type === 'curve' && flowLines.bottom.type === 'curve') { - startPointX = flowLines.bottom.y2 - (calcAreaWidth - totalModuleWidthCount * height) / 2 + startPointX = flowLines.bottom.y1 - (calcAreaWidth - totalModuleWidthCount * height) / 2 } let heightMargin = 0 @@ -2843,7 +2878,18 @@ export function useModuleBasicSetting(tabNum) { } } - moduleSetupSurfaces.forEach((moduleSetupSurface, index) => { + // 대칭 지붕을 위한 calcAreaWidth 공유 객체 (south→north, west→east) + const symmetricWidthRef = { south: null, west: null } + + // 대칭 보정을 위해 south/west가 north/east보다 먼저 처리되도록 정렬 + const directionOrder = { south: 0, west: 1, north: 2, east: 3 } + const sortedModuleSetupSurfaces = [...moduleSetupSurfaces].sort((a, b) => { + const orderA = directionOrder[a.direction] ?? 4 + const orderB = directionOrder[b.direction] ?? 4 + return orderA - orderB + }) + + sortedModuleSetupSurfaces.forEach((moduleSetupSurface, index) => { moduleSetupSurface.fire('mousedown') const moduleSetupArray = [] @@ -2869,30 +2915,30 @@ export function useModuleBasicSetting(tabNum) { if (setupLocation === 'eaves') { // 흐름방향이 남쪽일때 if (moduleSetupSurface.direction === 'south') { - downFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) + downFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer, symmetricWidthRef) } if (moduleSetupSurface.direction === 'west') { - leftFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) + leftFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer, symmetricWidthRef) } if (moduleSetupSurface.direction === 'east') { - rightFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) + rightFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer, symmetricWidthRef) } if (moduleSetupSurface.direction === 'north') { - topFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) + topFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer, symmetricWidthRef) } } else if (setupLocation === 'ridge') { //용마루 if (moduleSetupSurface.direction === 'south') { - topFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) + topFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer, symmetricWidthRef) } if (moduleSetupSurface.direction === 'west') { - rightFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) + rightFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer, symmetricWidthRef) } if (moduleSetupSurface.direction === 'east') { - leftFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) + leftFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer, symmetricWidthRef) } if (moduleSetupSurface.direction === 'north') { - downFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) + downFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer, symmetricWidthRef) } } @@ -3072,13 +3118,26 @@ export function useModuleBasicSetting(tabNum) { type: 'flat', } } else { - rtnObj = { - target: index === 0 ? 'bottom' : 'top', - x1: pointX1, - y1: pointY1, - x2: pointX2, - y2: pointY2, - type: 'curve', + // NaN 체크: offset이 너무 커서 꼭짓점을 넘어가면 NaN 발생 + if (isNaN(pointX1) || isNaN(pointX2) || isNaN(pointY1) || isNaN(pointY2)) { + // NaN이면 꼭짓점 좌표 사용 (모듈 설치 영역 없음) + rtnObj = { + target: index === 0 ? 'bottom' : 'top', + x1: center.x1, + y1: center.y1, + x2: center.x1, + y2: center.y1, + type: 'curve', + } + } else { + rtnObj = { + target: index === 0 ? 'bottom' : 'top', + x1: pointX1, + y1: pointY1, + x2: pointX2, + y2: pointY2, + type: 'curve', + } } } @@ -3204,13 +3263,26 @@ export function useModuleBasicSetting(tabNum) { type: 'flat', } } else { - rtnObj = { - target: index === 0 ? 'left' : 'right', - x1: pointX1, - y1: pointY1, - x2: pointX2, - y2: pointY2, - type: 'curve', + // NaN 체크: offset이 너무 커서 꼭짓점을 넘어가면 NaN 발생 + if (isNaN(pointX1) || isNaN(pointX2) || isNaN(pointY1) || isNaN(pointY2)) { + // NaN이면 꼭짓점 좌표 사용 (모듈 설치 영역 없음) + rtnObj = { + target: index === 0 ? 'left' : 'right', + x1: center.x1, + y1: center.y1, + x2: center.x1, + y2: center.y1, + type: 'curve', + } + } else { + rtnObj = { + target: index === 0 ? 'left' : 'right', + x1: pointX1, + y1: pointY1, + x2: pointX2, + y2: pointY2, + type: 'curve', + } } } rtnObjArray.push(rtnObj) @@ -4101,6 +4173,7 @@ export function useModuleBasicSetting(tabNum) { left: leftRightFlowLine(moduleSetupSurface, length).find((obj) => obj.target === 'left'), right: leftRightFlowLine(moduleSetupSurface, length).find((obj) => obj.target === 'right'), } + return flowLines } From 825fca0fa15fa58a5f2beae84a181b826af84248 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 2 Feb 2026 10:16:26 +0900 Subject: [PATCH 4/6] =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=BA=A1?= =?UTF-8?q?=EC=B3=90=20=EC=8B=9C=20=ED=95=B4=EC=83=81=EB=A0=A5=202?= =?UTF-8?q?=EB=B0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/floorPlan/useImgLoader.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/hooks/floorPlan/useImgLoader.js b/src/hooks/floorPlan/useImgLoader.js index 242206db..81383f13 100644 --- a/src/hooks/floorPlan/useImgLoader.js +++ b/src/hooks/floorPlan/useImgLoader.js @@ -58,7 +58,12 @@ export function useImgLoader() { canvas.renderAll() const formData = new FormData() - const dataUrl = canvas.toDataURL('image/png') + // 고해상도 캡처를 위해 multiplier 옵션 추가 (2배 해상도) + const multiplier = 2 + const dataUrl = canvas.toDataURL({ + format: 'png', + multiplier: multiplier, + }) const blobBin = atob(dataUrl.split(',')[1]) const array = [] for (let i = 0; i < blobBin.length; i++) { @@ -69,13 +74,13 @@ export function useImgLoader() { formData.append('objectNo', currentCanvasPlan.objectNo) formData.append('planNo', currentCanvasPlan.planNo) formData.append('type', type) - /** 이미지 크롭 좌표 계산 */ + /** 이미지 크롭 좌표 계산 (multiplier 배율 적용) */ const positionObj = getImageCoordinates() console.log('🚀 ~ handleCanvasToPng ~ positionObj:', positionObj) - formData.append('width', Math.round(positionObj[1].x - positionObj[0].x + 100)) - formData.append('height', Math.round(positionObj[1].y - positionObj[0].y + 100)) - formData.append('left', Math.round(positionObj[0].x)) - formData.append('top', Math.round(positionObj[0].y)) + formData.append('width', Math.round((positionObj[1].x - positionObj[0].x + 100) * multiplier)) + formData.append('height', Math.round((positionObj[1].y - positionObj[0].y + 100) * multiplier)) + formData.append('left', Math.round(positionObj[0].x * multiplier)) + formData.append('top', Math.round(positionObj[0].y * multiplier)) console.log('🚀 ~ handleCanvasToPng ~ formData:', formData) /** 이미지 크롭 요청 */ From d95e5d63e0409ab7a361f51c0a2a1886fdf97b4c Mon Sep 17 00:00:00 2001 From: ysCha Date: Mon, 2 Feb 2026 13:36:33 +0900 Subject: [PATCH 5/6] =?UTF-8?q?[1436]=EC=B2=98=EB=A7=88=20=EC=BB=A4?= =?UTF-8?q?=EB=B2=84=EC=9D=98=20=EC=B2=98=EC=9D=8C=20=EC=B2=B4=ED=81=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/modal/basic/step/Trestle.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/floor-plan/modal/basic/step/Trestle.jsx b/src/components/floor-plan/modal/basic/step/Trestle.jsx index 2ef723d0..17279d83 100644 --- a/src/components/floor-plan/modal/basic/step/Trestle.jsx +++ b/src/components/floor-plan/modal/basic/step/Trestle.jsx @@ -859,7 +859,7 @@ const Trestle = forwardRef((props, ref) => { type="checkbox" id={`ch01`} disabled={!cvrYn || cvrYn === 'N'} - checked={cvrChecked || true} + checked={cvrChecked ?? false} // onChange={() => dispatch({ type: 'SET_TRESTLE_DETAIL', roof: { ...trestleState, cvrChecked: !trestleState.cvrChecked } })} onChange={() => setCvrChecked(!cvrChecked)} /> From b4efbbeb7f51abc08cbd4467c9cb8aa03edf2e07 Mon Sep 17 00:00:00 2001 From: ysCha Date: Mon, 2 Feb 2026 14:24:52 +0900 Subject: [PATCH 6/6] =?UTF-8?q?[1436]=EC=B2=98=EB=A7=88=20=EC=BB=A4?= =?UTF-8?q?=EB=B2=84=EC=9D=98=20=EC=B2=98=EC=9D=8C=20=EC=B2=B4=ED=81=AC2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/modal/basic/step/Trestle.jsx | 2 +- src/hooks/module/useModuleTrestle.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/floor-plan/modal/basic/step/Trestle.jsx b/src/components/floor-plan/modal/basic/step/Trestle.jsx index 17279d83..19169e4f 100644 --- a/src/components/floor-plan/modal/basic/step/Trestle.jsx +++ b/src/components/floor-plan/modal/basic/step/Trestle.jsx @@ -413,7 +413,7 @@ const Trestle = forwardRef((props, ref) => { setCvrYn(constructionList[index].cvrYn) setSnowGdPossYn(constructionList[index].snowGdPossYn) - setCvrChecked(false) + setCvrChecked(true) setSnowGdChecked(false) } } diff --git a/src/hooks/module/useModuleTrestle.js b/src/hooks/module/useModuleTrestle.js index fc588d09..0d219401 100644 --- a/src/hooks/module/useModuleTrestle.js +++ b/src/hooks/module/useModuleTrestle.js @@ -61,7 +61,7 @@ export function useModuleTrestle(props) { const [lengthBase, setLengthBase] = useState(0) const [hajebichi, setHajebichi] = useState(0) const [cvrYn, setCvrYn] = useState('N') - const [cvrChecked, setCvrChecked] = useState(false) + const [cvrChecked, setCvrChecked] = useState(true) const [snowGdPossYn, setSnowGdPossYn] = useState('N') const [snowGdChecked, setSnowGdChecked] = useState(false) const [eavesMargin, setEavesMargin] = useState(0) @@ -88,7 +88,7 @@ export function useModuleTrestle(props) { setKerabaMargin(selectedRoof?.kerabaMargin ?? 0) setLengthBase(Math.round(selectedRoof?.length ?? 0)) setCvrYn(selectedRoof?.construction?.cvrYn ?? 'N') - setCvrChecked(selectedRoof?.construction?.cvrChecked ?? false) + setCvrChecked(selectedRoof?.construction?.cvrChecked ?? true) setSnowGdPossYn(selectedRoof?.construction?.snowGdPossYn ?? 'N') setSnowGdChecked(selectedRoof?.construction?.snowGdChecked ?? false) setTrestleDetail(selectedRoof?.trestleDetail)