dev #285

Merged
ysCha merged 4 commits from dev into prd-deploy 2025-08-20 08:52:42 +09:00
7 changed files with 187 additions and 85 deletions

View File

@ -120,7 +120,44 @@ export default function CircuitTrestleSetting({ id }) {
const beforeCapture = (type) => { const beforeCapture = (type) => {
setCanvasZoom(100) setCanvasZoom(100)
canvas.set({ zoom: 1 }) canvas.set({ zoom: 1 })
canvas.viewportTransform = [1, 0, 0, 1, 0, 0]
// roof
const roofs = canvas.getObjects().filter((obj) => obj.name === 'roof')
if (roofs.length > 0) {
// roof x, y
const allPoints = []
roofs.forEach((roof) => {
if (roof.getCurrentPoints()) {
roof.getCurrentPoints().forEach((point) => {
allPoints.push({ x: point.x, y: point.y })
})
}
})
if (allPoints.length > 0) {
//
const minX = Math.min(...allPoints.map((p) => p.x))
const maxX = Math.max(...allPoints.map((p) => p.x))
const minY = Math.min(...allPoints.map((p) => p.y))
const maxY = Math.max(...allPoints.map((p) => p.y))
const centerX = (minX + maxX) / 2
const centerY = (minY + maxY) / 2
//
const canvasWidth = canvas.getWidth()
const canvasHeight = canvas.getHeight()
const offsetX = canvasWidth / 2 - centerX
const offsetY = canvasHeight / 2 - centerY
canvas.viewportTransform = [1, 0, 0, 1, offsetX, offsetY]
} else {
canvas.viewportTransform = [1, 0, 0, 1, 0, 0]
}
} else {
canvas.viewportTransform = [1, 0, 0, 1, 0, 0]
}
const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE) const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
const circuitNumberTexts = canvas.getObjects().filter((obj) => obj.name === 'circuitNumber') const circuitNumberTexts = canvas.getObjects().filter((obj) => obj.name === 'circuitNumber')
@ -139,40 +176,9 @@ export default function CircuitTrestleSetting({ id }) {
// roof polygon // roof polygon
const roofPolygons = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) const roofPolygons = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
let x, y let x, y
x = 0 //canvas.width / 2 x = canvas.width / 2
y = 1000 //canvas.height / 2 y = canvas.height / 2
/*if (roofPolygons.length > 0) {
let minX = Infinity,
minY = Infinity,
maxX = -Infinity,
maxY = -Infinity
roofPolygons.forEach((obj) => {
const boundingRect = obj.getBoundingRect()
minX = Math.min(minX, boundingRect.left)
minY = Math.min(minY, boundingRect.top)
maxX = Math.max(maxX, boundingRect.left + boundingRect.width)
maxY = Math.max(maxY, boundingRect.top + boundingRect.height)
})
x = (minX + maxX) / 2
y = (minY + maxY) / 2
} else {
// roof polygon
x = canvas.width / 2
y = canvas.height / 2
}
if (x > 1600) {
x = 0
y = 0
}
if (y > 1600) {
x = 0
y = 0
}*/
canvas.zoomToPoint(new fabric.Point(x, y), 0.4) canvas.zoomToPoint(new fabric.Point(x, y), 0.4)
changeFontSize('lengthText', '28') changeFontSize('lengthText', '28')
changeFontSize('circuitNumber', '28') changeFontSize('circuitNumber', '28')

View File

@ -5,9 +5,9 @@ import { useRecoilValue } from 'recoil'
import { contextPopupPositionState } from '@/store/popupAtom' import { contextPopupPositionState } from '@/store/popupAtom'
import { useState } from 'react' import { useState } from 'react'
import { canvasState, currentObjectState } from '@/store/canvasAtom' import { canvasState, currentObjectState } from '@/store/canvasAtom'
import { useGrid } from '@/hooks/common/useGrid'
import { gridColorState } from '@/store/gridAtom' import { gridColorState } from '@/store/gridAtom'
import { gridDisplaySelector } from '@/store/settingAtom' import { gridDisplaySelector } from '@/store/settingAtom'
const GRID_PADDING = 5 const GRID_PADDING = 5
export default function GridCopy(props) { export default function GridCopy(props) {
const contextPopupPosition = useRecoilValue(contextPopupPositionState) const contextPopupPosition = useRecoilValue(contextPopupPositionState)
@ -25,10 +25,10 @@ export default function GridCopy(props) {
} }
const copy = (object, length) => { const copy = (object, length) => {
const lineStartX = object.direction === 'vertical' ? object.x1 + length : 0 const lineStartX = object.direction === 'vertical' ? object.x1 + length : object.x1
const lineEndX = object.direction === 'vertical' ? object.x2 + length : canvas.width const lineEndX = object.direction === 'vertical' ? object.x2 + length : object.x2
const lineStartY = object.direction === 'vertical' ? 0 : object.y1 + length const lineStartY = object.direction === 'vertical' ? object.y1 : object.y1 + length
const lineEndY = object.direction === 'vertical' ? canvas.width : object.y1 + length const lineEndY = object.direction === 'vertical' ? object.y2 : object.y1 + length
const line = new fabric.Line([lineStartX, lineStartY, lineEndX, lineEndY], { const line = new fabric.Line([lineStartX, lineStartY, lineEndX, lineEndY], {
stroke: gridColor, stroke: gridColor,

View File

@ -3,11 +3,9 @@ import { useMessage } from '@/hooks/useMessage'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
import { contextPopupPositionState } from '@/store/popupAtom' import { contextPopupPositionState } from '@/store/popupAtom'
import { useCanvas } from '@/hooks/useCanvas'
import { canvasState, currentObjectState } from '@/store/canvasAtom' import { canvasState, currentObjectState } from '@/store/canvasAtom'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'
import { set } from 'react-hook-form'
export default function GridMove(props) { export default function GridMove(props) {
const contextPopupPosition = useRecoilValue(contextPopupPositionState) const contextPopupPosition = useRecoilValue(contextPopupPositionState)
@ -70,10 +68,10 @@ export default function GridMove(props) {
const move = (object, x, y) => { const move = (object, x, y) => {
object.set({ object.set({
...object, ...object,
x1: object.direction === 'vertical' ? object.x1 + x : 0, x1: object.direction === 'vertical' ? object.x1 + x : object.x1,
x2: object.direction === 'vertical' ? object.x1 + x : canvas.width, x2: object.direction === 'vertical' ? object.x1 + x : object.x2,
y1: object.direction === 'vertical' ? 0 : object.y1 + y, y1: object.direction === 'vertical' ? object.y1 : object.y1 + y,
y2: object.direction === 'vertical' ? canvas.height : object.y1 + y, y2: object.direction === 'vertical' ? object.y2 : object.y1 + y,
}) })
} }

View File

@ -1,15 +1,18 @@
import { useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
import { canvasState, dotLineGridSettingState } from '@/store/canvasAtom' import { canvasState, canvasZoomState, dotLineGridSettingState } from '@/store/canvasAtom'
import { useEffect } from 'react' import { useEffect } from 'react'
import { gridColorState } from '@/store/gridAtom' import { gridColorState } from '@/store/gridAtom'
import { gridDisplaySelector } from '@/store/settingAtom' import { gridDisplaySelector } from '@/store/settingAtom'
const GRID_PADDING = 5 const GRID_PADDING = 5
export function useGrid() { export function useGrid() {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const dotLineGridSetting = useRecoilValue(dotLineGridSettingState) const dotLineGridSetting = useRecoilValue(dotLineGridSettingState)
const gridColor = useRecoilValue(gridColorState) const gridColor = useRecoilValue(gridColorState)
const isGridDisplay = useRecoilValue(gridDisplaySelector) const isGridDisplay = useRecoilValue(gridDisplaySelector)
const zoom = useRecoilValue(canvasZoomState)
useEffect(() => { useEffect(() => {
if (!canvas) { if (!canvas) {
@ -90,14 +93,32 @@ export function useGrid() {
} }
if (patternData.lineGridDisplay) { if (patternData.lineGridDisplay) {
for (let i = 0; i < 5000 / patternData.gridVertical + 1; i++) { // 캔버스의 실제 보이는 영역 계산
const canvasWidth = canvas.getWidth()
const canvasHeight = canvas.getHeight()
const currentZoom = canvas.getZoom()
const viewportTransform = canvas.viewportTransform
const visibleLeft = -viewportTransform[4] / currentZoom
const visibleTop = -viewportTransform[5] / currentZoom
const visibleRight = visibleLeft + canvasWidth / currentZoom
const visibleBottom = visibleTop + canvasHeight / currentZoom
// 여유 공간 추가
const padding = 200
const gridLeft = visibleLeft - padding
const gridTop = visibleTop - padding
const gridRight = visibleRight + padding
const gridBottom = visibleBottom + padding
// 가로선 생성 (수평선)
const horizontalGridRange = gridBottom - gridTop
const horizontalGridCount = Math.ceil(horizontalGridRange / patternData.gridVertical) + 2
for (let i = 0; i < horizontalGridCount; i++) {
const y = gridTop + i * patternData.gridVertical
const horizontalLine = new fabric.Line( const horizontalLine = new fabric.Line(
[ [gridLeft, y, gridRight, y],
-1500,
-1500 + i * patternData.gridVertical - patternData.gridVertical / 2,
3000,
-1500 + i * patternData.gridVertical - patternData.gridVertical / 2,
],
{ {
stroke: gridColor, stroke: gridColor,
strokeWidth: 1, strokeWidth: 1,
@ -118,14 +139,14 @@ export function useGrid() {
canvas.add(horizontalLine) canvas.add(horizontalLine)
} }
for (let i = 0; i < 5000 / patternData.gridHorizon + 1; i++) { // 세로선 생성 (수직선)
const verticalGridRange = gridRight - gridLeft
const verticalGridCount = Math.ceil(verticalGridRange / patternData.gridHorizon) + 2
for (let i = 0; i < verticalGridCount; i++) {
const x = gridLeft + i * patternData.gridHorizon
const verticalLine = new fabric.Line( const verticalLine = new fabric.Line(
[ [x, gridTop, x, gridBottom],
-1500 + i * patternData.gridHorizon - patternData.gridHorizon / 2,
-1500,
-1500 + i * patternData.gridHorizon - patternData.gridHorizon / 2,
3000,
],
{ {
stroke: gridColor, stroke: gridColor,
strokeWidth: 1, strokeWidth: 1,
@ -148,7 +169,7 @@ export function useGrid() {
} }
canvas.renderAll() canvas.renderAll()
}, [dotLineGridSetting]) }, [dotLineGridSetting, zoom])
const move = (object, x, y) => { const move = (object, x, y) => {
object.set({ object.set({

View File

@ -1,29 +1,29 @@
import { useEffect, useState, useRef, useContext } from 'react' import { useContext, useEffect, useState } from 'react'
import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil' import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
import { import {
adsorptionPointModeState, adsorptionPointModeState,
adsorptionRangeState, adsorptionRangeState,
canvasState,
planSizeSettingState,
dotLineGridSettingState,
canvasSettingState, canvasSettingState,
canvasState,
currentMenuState, currentMenuState,
dotLineGridSettingState,
planSizeSettingState,
} from '@/store/canvasAtom' } from '@/store/canvasAtom'
import { globalLocaleStore } from '@/store/localeAtom' import { globalLocaleStore } from '@/store/localeAtom'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'
import { import {
addedRoofsState,
basicSettingState,
correntObjectNoState, correntObjectNoState,
corridorDimensionSelector, corridorDimensionSelector,
settingModalFirstOptionsState, fetchRoofMaterialsState,
settingModalSecondOptionsState,
settingModalGridOptionsState,
basicSettingState,
roofMaterialsAtom, roofMaterialsAtom,
selectedRoofMaterialSelector, selectedRoofMaterialSelector,
addedRoofsState, settingModalFirstOptionsState,
fetchRoofMaterialsState, settingModalGridOptionsState,
settingModalSecondOptionsState,
} from '@/store/settingAtom' } from '@/store/settingAtom'
import { MENU, POLYGON_TYPE } from '@/common/common' import { MENU, POLYGON_TYPE } from '@/common/common'
import { globalFontAtom } from '@/store/fontAtom' import { globalFontAtom } from '@/store/fontAtom'
@ -339,11 +339,11 @@ export function useCanvasSetting(executeEffect = true) {
*/ */
const fetchBasicSettings = async (planNo, openPoint) => { const fetchBasicSettings = async (planNo, openPoint) => {
// 지붕재 데이터가 없으면 먼저 로드 // 지붕재 데이터가 없으면 먼저 로드
let materials = roofMaterials; let materials = roofMaterials
if (!materials || materials.length === 0) { if (!materials || materials.length === 0) {
logger.log("Waiting for roofMaterials to be loaded..."); logger.log('Waiting for roofMaterials to be loaded...')
materials = await addRoofMaterials(); materials = await addRoofMaterials()
logger.log("roofMaterials loaded:", materials); logger.log('roofMaterials loaded:', materials)
} }
try { try {
@ -529,8 +529,14 @@ export function useCanvasSetting(executeEffect = true) {
? params.selectedRoofMaterial.raftBaseCd ? params.selectedRoofMaterial.raftBaseCd
: params.roofsData.raft, : params.roofsData.raft,
roofLayout: params.roofsData.roofLayout === null || params.roofsData.roofLayout === undefined ? 'P' : params.roofsData.roofLayout, roofLayout: params.roofsData.roofLayout === null || params.roofsData.roofLayout === undefined ? 'P' : params.roofsData.roofLayout,
roofPitch: params.roofsData.roofPitch === null || params.roofsData.roofPitch === undefined || params.roofsData.roofPitch === '' ? 0 : params.roofsData.roofPitch, roofPitch:
roofAngle: params.roofsData.roofAngle === null || params.roofsData.roofAngle === undefined || params.roofsData.roofAngle === '' ? 0 : params.roofsData.roofAngle, params.roofsData.roofPitch === null || params.roofsData.roofPitch === undefined || params.roofsData.roofPitch === ''
? 0
: params.roofsData.roofPitch,
roofAngle:
params.roofsData.roofAngle === null || params.roofsData.roofAngle === undefined || params.roofsData.roofAngle === ''
? 0
: params.roofsData.roofAngle,
}, },
], ],
} }
@ -643,7 +649,11 @@ export function useCanvasSetting(executeEffect = true) {
setDimensionLineSettings({ ...dimensionLineSettings, pixel: res.originPixel, color: res.originColor }) setDimensionLineSettings({ ...dimensionLineSettings, pixel: res.originPixel, color: res.originColor })
/** 도면크기 설정 */ /** 도면크기 설정 */
setPlanSizeSettingMode({ ...planSizeSettingMode, originHorizon: res.originHorizon, originVertical: res.originVertical }) setPlanSizeSettingMode({
...planSizeSettingMode,
originHorizon: res.originHorizon,
originVertical: res.originVertical,
})
canvas.setWidth(res.originHorizon) canvas.setWidth(res.originHorizon)
canvas.setHeight(res.originVertical) canvas.setHeight(res.originVertical)
canvas.renderAll() canvas.renderAll()
@ -723,7 +733,7 @@ export function useCanvasSetting(executeEffect = true) {
/** 조회된 글꼴 데이터가 없는 경우 (데이터 초기화) */ /** 조회된 글꼴 데이터가 없는 경우 (데이터 초기화) */
/** 흡착점 ON/OFF */ /** 흡착점 ON/OFF */
setAdsorptionPointMode(false) setAdsorptionPointMode(true)
/** 치수선 설정 */ /** 치수선 설정 */
resetDimensionLineSettings() resetDimensionLineSettings()

View File

@ -26,6 +26,7 @@ export function useCanvas(id) {
const isImageDisplay = useRecoilValue(imageDisplaySelector) const isImageDisplay = useRecoilValue(imageDisplaySelector)
const {} = useFont() const {} = useFont()
const resetCanvasZoom = useResetRecoilState(canvasZoomState) const resetCanvasZoom = useResetRecoilState(canvasZoomState)
const zoom = useRecoilValue(canvasZoomState)
/** /**
* 처음 셋팅 * 처음 셋팅
@ -50,8 +51,53 @@ export function useCanvas(id) {
}, []) }, [])
useEffect(() => { useEffect(() => {
// canvas 사이즈가 변경되면 다시 // zoom 상태가 변경될 때 tempGrid 라인들의 크기를 캔버스에 맞게 조정
}, [canvasSize]) if (canvas) {
adjustTempGridLines()
}
}, [zoom])
const adjustTempGridLines = () => {
if (!canvas) return
const canvasWidth = canvas.getWidth()
const canvasHeight = canvas.getHeight()
const currentZoom = canvas.getZoom()
const viewportTransform = canvas.viewportTransform
// 실제 보이는 캔버스 영역 계산 (zoom과 pan 고려)
const visibleLeft = -viewportTransform[4] / currentZoom
const visibleTop = -viewportTransform[5] / currentZoom
const visibleRight = visibleLeft + canvasWidth / currentZoom
const visibleBottom = visibleTop + canvasHeight / currentZoom
// tempGrid 라인들을 찾아서 크기 조정
const tempGridLines = canvas.getObjects().filter((obj) => ['tempGrid', 'lineGrid', 'mouseLine'].includes(obj.name))
tempGridLines.forEach((line) => {
if (line.direction === 'vertical') {
// 세로 라인: y축을 캔버스 전체 높이로 설정
line.set({
x1: line.x1,
y1: visibleTop - 100, // 여유 공간 추가
x2: line.x1,
y2: visibleBottom + 100, // 여유 공간 추가
})
} else if (line.direction === 'horizontal') {
// 가로 라인: x축을 캔버스 전체 너비로 설정
line.set({
x1: visibleLeft - 100, // 여유 공간 추가
y1: line.y1,
x2: visibleRight + 100, // 여유 공간 추가
y2: line.y1,
})
}
line.setCoords()
})
canvas.renderAll()
}
useEffect(() => { useEffect(() => {
canvas canvas

View File

@ -369,18 +369,39 @@ export function useEvent() {
} }
const drawMouseLine = (pointer) => { const drawMouseLine = (pointer) => {
const horizontalLine = new fabric.Line([-2 * canvas.width, pointer.y, 2 * canvas.width, pointer.y], { // 캔버스의 실제 보이는 영역 계산 (zoom과 pan 고려)
const canvasWidth = canvas.getWidth()
const canvasHeight = canvas.getHeight()
const currentZoom = canvas.getZoom()
const viewportTransform = canvas.viewportTransform
const visibleLeft = -viewportTransform[4] / currentZoom
const visibleTop = -viewportTransform[5] / currentZoom
const visibleRight = visibleLeft + canvasWidth / currentZoom
const visibleBottom = visibleTop + canvasHeight / currentZoom
// 여유 공간 추가
const padding = 200
const lineLeft = visibleLeft - padding
const lineTop = visibleTop - padding
const lineRight = visibleRight + padding
const lineBottom = visibleBottom + padding
// 가로선 (수평선)
const horizontalLine = new fabric.Line([lineLeft, pointer.y, lineRight, pointer.y], {
stroke: 'red', stroke: 'red',
strokeWidth: 1, strokeWidth: 1,
selectable: false, selectable: false,
direction: 'horizontal',
name: 'mouseLine', name: 'mouseLine',
}) })
// 세로선 // 세로선 (수직선)
const verticalLine = new fabric.Line([pointer.x, -2 * canvas.height, pointer.x, 2 * canvas.height], { const verticalLine = new fabric.Line([pointer.x, lineTop, pointer.x, lineBottom], {
stroke: 'red', stroke: 'red',
strokeWidth: 1, strokeWidth: 1,
selectable: false, selectable: false,
direction: 'vertical',
name: 'mouseLine', name: 'mouseLine',
}) })