diff --git a/src/components/ui/SurfaceShape.jsx b/src/components/ui/SurfaceShape.jsx
index 01c557ff..3923108d 100644
--- a/src/components/ui/SurfaceShape.jsx
+++ b/src/components/ui/SurfaceShape.jsx
@@ -1,4 +1,3 @@
-import { Button, Input } from '@nextui-org/react'
import { useState } from 'react'
import { useRecoilValue, useSetRecoilState } from 'recoil'
import { modalState } from '@/store/modalAtom'
@@ -780,9 +779,9 @@ export const SurfaceShapeModal = ({ canvas }) => {
const buttons = []
for (let i = 1; i <= 29; i++) {
buttons.push(
-
,
)
}
@@ -798,97 +797,97 @@ export const SurfaceShapeModal = ({ canvas }) => {
{type === 1 ? (
길이1
-
+
{length3 === 0 && (
<>
길이2
-
+
>
)}
- 대각선
+ 대각선
) : [2, 4, 5].includes(type) ? (
길이1
-
+
길이2
-
+
) : [3, 6, 7, 8, 9, 24, 28, 29].includes(type) ? (
<>
길이1
-
+
길이2
-
+
길이3
-
+
>
) : [11, 12, 19, 20, 21, 22, 25, 26, 27].includes(type) ? (
<>
길이1
-
+
길이2
-
+
길이3
-
+
길이4
-
+
>
) : [10, 13, 14, 15, 16, 17, 18, 23].includes(type) ? (
<>
길이1
-
+
길이2
-
+
길이3
-
+
길이4
-
+
길이5
-
+
>
) : (
<>>
)}
- setDirection('north')}
>
북
-
+
- setDirection('west')}
>
서
-
-
+ setDirection('east')}
>
동
-
+
- setDirection('south')}
>
남
-
+
-
+
닫기
-
-
+
+
저장
-
+
>
)
diff --git a/src/components/ui/ThumbnailLIst.jsx b/src/components/ui/ThumbnailLIst.jsx
deleted file mode 100644
index 1d67dbe8..00000000
--- a/src/components/ui/ThumbnailLIst.jsx
+++ /dev/null
@@ -1,38 +0,0 @@
-'use client'
-
-import { memo } from 'react'
-import { Card, Image } from '@nextui-org/react'
-
-function ThumbnailList(props) {
- const { thumbnails, canvas } = props
-
- const handleSelectThumb = (canvasStatus) => {
- console.log('canvasStatus', canvasStatus.length)
- canvas?.clear() // 캔버스를 초기화합니다.
- canvas?.loadFromJSON(JSON.parse(canvasStatus), function () {
- canvas?.renderAll() // 캔버스를 다시 그립니다.
- })
- }
-
- return (
- <>
-
- {thumbnails.length > 0 &&
- thumbnails.map((thumbnail, index) => (
-
- handleSelectThumb(thumbnail.canvasStatus)}
- />
-
- ))}
-
- >
- )
-}
-
-export default memo(ThumbnailList)
diff --git a/src/hooks/common/useCanvasConfigInitialize.js b/src/hooks/common/useCanvasConfigInitialize.js
index 089aeea9..91d65edb 100644
--- a/src/hooks/common/useCanvasConfigInitialize.js
+++ b/src/hooks/common/useCanvasConfigInitialize.js
@@ -9,6 +9,7 @@ import { globalFontAtom } from '@/store/fontAtom'
import { useRoof } from '@/hooks/common/useRoof'
import { usePolygon } from '@/hooks/usePolygon'
import { useRoofFn } from '@/hooks/common/useRoofFn'
+import { POLYGON_TYPE } from '@/common/common'
export function useCanvasConfigInitialize() {
const canvas = useRecoilValue(canvasState)
@@ -23,7 +24,7 @@ export function useCanvasConfigInitialize() {
const {} = useFont()
const {} = useGrid()
const {} = useRoof()
- const { drawDirectionArrow } = usePolygon()
+ const { drawDirectionArrow, addLengthText } = usePolygon()
useEffect(() => {
if (!canvas) return
@@ -160,11 +161,15 @@ export function useCanvasConfigInitialize() {
const objectsParentId = canvas.getObjects().filter((obj) => obj.groupId === id || obj.id === id)[0].parentId
let objectArray = []
+ let groupPoints = []
//그룹객체가 있으면 배열에 추가함
if (groupObjects) {
groupObjects.forEach((obj) => {
objectArray.push(obj)
+ if (obj.groupPoints) {
+ groupPoints = obj.groupPoints
+ }
})
}
@@ -187,25 +192,40 @@ export function useCanvasConfigInitialize() {
})
canvas.add(group)
+ //도머등 그룹에 포인트가 있는애들한테 다시 넣어준다
+ if (groupPoints.length > 0) {
+ group.set({
+ groupPoints: groupPoints,
+ })
+ }
+
//그룹 객체 재그룹 완료
group.getObjects().forEach((obj) => {
obj.fire('modified')
+ if (obj.texts) {
+ obj.texts.forEach((text) => {
+ text.bringToFront()
+ })
+ }
})
})
}
const moduleInit = () => {
- canvas
- .getObjects()
- .filter((obj) => obj.name === 'module')
- .forEach((obj) => {
- obj.set({
- selectable: true,
- lockMovementX: true,
- lockMovementY: true,
- })
- obj.setViewLengthText(false)
+ const roofSurfaceList = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
+ const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
+ roofSurfaceList.forEach((surface) => {
+ surface.modules = modules.filter((module) => module.surfaceId === surface.id)
+ })
+ modules.forEach((obj) => {
+ console.log(obj)
+ obj.set({
+ selectable: true,
+ lockMovementX: true,
+ lockMovementY: true,
})
+ obj.setViewLengthText(false)
+ })
}
return { canvasLoadInit, gridInit }
diff --git a/src/hooks/common/useCanvasMenu.js b/src/hooks/common/useCanvasMenu.js
index 0fb1e87d..f90881d3 100644
--- a/src/hooks/common/useCanvasMenu.js
+++ b/src/hooks/common/useCanvasMenu.js
@@ -1,4 +1,4 @@
-import { menuNumberState } from '@/store/menuAtom'
+import { selectedMenuState } from '@/store/menuAtom'
import { useRecoilState, useRecoilValue } from 'recoil'
import { useEffect } from 'react'
import { canvasState } from '@/store/canvasAtom'
@@ -6,28 +6,12 @@ import { usePolygon } from '@/hooks/usePolygon'
import { POLYGON_TYPE } from '@/common/common'
export const useCanvasMenu = () => {
- const [menuNumber, setMenuNumber] = useRecoilState(menuNumberState)
+ const [selectedMenu, setSelectedMenu] = useRecoilState(selectedMenuState)
const canvas = useRecoilValue(canvasState)
const { drawDirectionArrow } = usePolygon()
- /*useEffect(() => {
- /!*
- * 모듈,회로 구성을 벗어나면 방향 표시 초기화 필요
- * *!/
- if (!canvas) return
- if (![4, 5].includes(menuNumber)) {
- canvas
- .getObjects()
- .filter((obj) => obj.name === POLYGON_TYPE.ROOF)
- .forEach((obj) => {
- obj.set('moduleCompass', null)
- // drawDirectionArrow(obj)
- })
- }
- }, [menuNumber])*/
-
return {
- menuNumber,
- setMenuNumber,
+ selectedMenu,
+ setSelectedMenu,
}
}
diff --git a/src/hooks/common/useCanvasPopupStatusController.js b/src/hooks/common/useCanvasPopupStatusController.js
index c6be7f9c..a31bd0ed 100644
--- a/src/hooks/common/useCanvasPopupStatusController.js
+++ b/src/hooks/common/useCanvasPopupStatusController.js
@@ -1,16 +1,21 @@
'use client'
import { useRecoilState, useRecoilValue } from 'recoil'
-import useSWR from 'swr'
import useSWRMutation from 'swr/mutation'
import { useAxios } from '../useAxios'
import { unescapeString } from '@/util/common-utils'
-import { moduleSelectionDataState, moduleSelectionTotalState, selectedModuleOptionsState, selectedModuleState } from '@/store/selectedModuleOptions'
+import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { compasDegAtom } from '@/store/orientationAtom'
import { canvasState, currentCanvasPlanState } from '@/store/canvasAtom'
import { POLYGON_TYPE } from '@/common/common'
-import { DateRangePickerField } from '@nextui-org/react'
+import { useCircuitTrestle } from '../useCirCuitTrestle'
+import { useEffect } from 'react'
+/**
+ * 캔버스 팝업 상태 관리
+ * @param {*} param
+ * @returns
+ */
export function useCanvasPopupStatusController(param = 1) {
const popupType = parseInt(param)
@@ -20,7 +25,6 @@ export function useCanvasPopupStatusController(param = 1) {
const { get, promiseGet, getFetcher, postFetcher } = useAxios()
const canvas = useRecoilValue(canvasState)
const currentCanvasPlan = useRecoilValue(currentCanvasPlanState)
- // console.log('🚀 ~ Orientation ~ currentCanvasPlan:', currentCanvasPlan)
/**
* 팝업 상태 조회
@@ -28,15 +32,6 @@ export function useCanvasPopupStatusController(param = 1) {
* @returns
*/
const getModuleSelection = async (popupTypeParam) => {
- // const {
- // data: popupStatus,
- // error,
- // isLoading,
- // } = useSWR(
- // `/api/v1/canvas-popup-status?objectNo=${currentCanvasPlan.objectNo}&planNo=${currentCanvasPlan.planNo}&popupType=${popupTypeParam}`,
- // getFetcher,
- // )
-
const result = await promiseGet({
url: `/api/v1/canvas-popup-status?objectNo=${currentCanvasPlan.objectNo}&planNo=${currentCanvasPlan.planNo}&popupType=${popupTypeParam}`,
})
@@ -59,67 +54,22 @@ export function useCanvasPopupStatusController(param = 1) {
for (let i = 1; i < 3; i++) {
const result = await getModuleSelection(i)
console.log('🚀 ~ handleModuleSelectionTotal ~ result:', result)
- // setModuleSelectionTotal((prev) => ({ ...prev, [i]: JSON.parse(unescapeString(result.popupStatus)) }))
if (!result.objectNo) return
if (i === 1) {
setCompasDeg(result.popupStatus)
} else if (i === 2) {
const data = JSON.parse(unescapeString(result.popupStatus))
setModuleSelectionDataStore(data)
- if (data.module) setSelectedModules(data.module)
-
const roofSurfaceList = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
roofSurfaceList.forEach((surface) => {
surface.modules = modules.filter((module) => module.surfaceId === surface.id)
})
+ if (data.module) setSelectedModules(data.module)
}
}
}
- // useEffect(() => {
- // if (popupStatus) {
- // switch (parseInt(popupStatus?.popupType)) {
- // case 1:
- // setCompasDeg(popupStatus.popupStatus)
- // break
- // case 2:
- // setModuleSelectionDataStore(JSON.parse(unescapeString(popupStatus.popupStatus)))
- // break
- // case 3:
- // break
- // case 4:
- // break
- // case 5:
- // break
- // case 6:
- // break
- // default:
- // }
- // } else {
- // switch (popupType) {
- // case 1:
- // setCompasDeg(0)
- // break
- // case 2:
- // setModuleSelectionDataStore({
- // common: {},
- // roofConstructions: [],
- // })
- // break
- // case 3:
- // break
- // case 4:
- // break
- // case 5:
- // break
- // case 6:
- // break
- // default:
- // }
- // }
- // }, [popupStatus])
-
/**
* 팝업 상태 저장
*/
@@ -136,5 +86,5 @@ export function useCanvasPopupStatusController(param = 1) {
},
)
- return { handleModuleSelectionTotal, trigger }
+ return { getModuleSelection, handleModuleSelectionTotal, trigger }
}
diff --git a/src/hooks/common/useCommonCode.js b/src/hooks/common/useCommonCode.js
index fc902ef2..e85cbb64 100644
--- a/src/hooks/common/useCommonCode.js
+++ b/src/hooks/common/useCommonCode.js
@@ -33,6 +33,8 @@ export const useCommonCode = () => {
clCode: code.clCode,
clCodeNm: globalLocale === 'ko' ? code.clCodeNm : code.clCodeJp,
clPriority: code.clPriority,
+ clRefChr1: code.clRefChr1,
+ clRefChr2: code.clRefChr2,
}
return result
})
diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js
index baaa7dfe..d5c1bd01 100644
--- a/src/hooks/common/useCommonUtils.js
+++ b/src/hooks/common/useCommonUtils.js
@@ -10,21 +10,23 @@ import { v4 as uuidv4 } from 'uuid'
import { usePopup } from '@/hooks/usePopup'
import Distance from '@/components/floor-plan/modal/distance/Distance'
import { usePolygon } from '@/hooks/usePolygon'
+import { useObjectBatch } from '@/hooks/object/useObjectBatch'
+import { BATCH_TYPE } from '@/common/common'
export function useCommonUtils() {
const canvas = useRecoilValue(canvasState)
const wordDisplay = useRecoilValue(wordDisplaySelector)
const { addCanvasMouseEventListener, addDocumentEventListener, initEvent } = useEvent()
- // const { addCanvasMouseEventListener, addDocumentEventListener, initEvent } = useContext(EventContext)
const dimensionSettings = useRecoilValue(dimensionLineSettingsState)
const dimensionLineTextFont = useRecoilValue(fontSelector('dimensionLineText'))
+ const lengthTextFont = useRecoilValue(fontSelector('lengthText'))
const commonTextFont = useRecoilValue(fontSelector('commonText'))
const [commonUtils, setCommonUtilsState] = useRecoilState(commonUtilsState)
const { addPopup } = usePopup()
const { drawDirectionArrow, addLengthText } = usePolygon()
+ const { applyDormers } = useObjectBatch({})
useEffect(() => {
- // initEvent()
if (commonUtils.text) {
commonTextMode()
} else if (commonUtils.dimension) {
@@ -247,15 +249,12 @@ export function useCommonUtils() {
name: 'extendLine',
id: uuid,
})
- // canvas.add(extendLine)
groupObjects.push(extendLine)
})
const dimensionPosition = calcDimensionPosition(lineDirection, p1CenterX, p1CenterY, p2CenterX, p2CenterY)
const arrow1 = createDimensionArrow(dimensionPosition.paddingX, dimensionPosition.paddingY, dimensionPosition.angle1, uuid) // 반대 방향 화살표
const arrow2 = createDimensionArrow(dimensionPosition.paddingX2, dimensionPosition.paddingY2, dimensionPosition.angle2, uuid) // 정방향 화살표
- // canvas.add(arrow1)
- // canvas.add(arrow2)
groupObjects.push(arrow1, arrow2)
@@ -287,6 +286,10 @@ export function useCommonUtils() {
originY: 'center',
lineDirection: lineDirection,
groupId: uuid,
+ length: distance * 10,
+ slopeAble: false,
+ angle1: null,
+ angle2: null,
})
canvas.add(group)
@@ -310,23 +313,6 @@ export function useCommonUtils() {
// 캔버스 다시 그리기
canvas.renderAll()
})
-
- // addCanvasMouseEventListener('object:moving', function (e) {
- // const obj = e.target
-
- // if (obj.left < minX) {
- // obj.left = minX
- // }
- // if (obj.left + obj.width > maxX) {
- // obj.left = maxX - obj.width
- // }
- // if (obj.top < minY) {
- // obj.top = minY
- // }
- // if (obj.top + obj.height > maxY) {
- // obj.top = maxY - obj.height
- // }
- // })
}
}
@@ -575,53 +561,79 @@ export function useCommonUtils() {
const commonCopyObject = (obj) => {
if (obj) {
- let clonedObj = null
+ //도머는 복사하기 보다 새로 호출해서 만드는 방법으로 함
+ if (obj.name == BATCH_TYPE.TRIANGLE_DORMER || obj.name == BATCH_TYPE.PENTAGON_DORMER) {
+ //그룹 객체 0번에 도머 속성을 넣어둠
+ const dormerAttributes = obj._objects[0].dormerAttributes
+ const dormerName = obj._objects[0].name
- obj.clone((cloned) => {
- clonedObj = cloned
- })
-
- addCanvasMouseEventListener('mouse:move', (e) => {
- const pointer = canvas?.getPointer(e.e)
- if (!clonedObj) return
-
- canvas
- .getObjects()
- .filter((obj) => obj.name === 'clonedObj')
- .forEach((obj) => canvas?.remove(obj))
-
- clonedObj.set({
- left: pointer.x,
- top: pointer.y,
- name: 'clonedObj',
- })
- canvas.add(clonedObj)
- })
-
- addCanvasMouseEventListener('mouse:down', (e) => {
- clonedObj.set({
- lockMovementX: true,
- lockMovementY: true,
- name: obj.name,
- editable: false,
- id: uuidv4(), //복사된 객체라 새로 따준다
- })
-
- //객체가 그룹일 경우에는 그룹 아이디를 따로 넣어준다
- if (clonedObj.type === 'group') clonedObj.set({ groupId: uuidv4() })
-
- //배치면일 경우
- if (obj.name === 'roof') {
- clonedObj.setCoords()
- clonedObj.fire('polygonMoved')
- clonedObj.set({ direction: obj.direction, directionText: obj.directionText })
- canvas.renderAll()
- addLengthText(clonedObj) //수치 추가
- drawDirectionArrow(clonedObj) //방향 화살표 추가
+ const dormerParams = {
+ height: dormerAttributes.height,
+ width: dormerAttributes.width,
+ pitch: dormerAttributes.pitch,
+ offsetRef: dormerAttributes.offsetRef,
+ offsetWidthRef: dormerAttributes.offsetWidthRef,
+ directionRef: dormerAttributes.directionRef,
}
- initEvent()
- })
+ const buttonAct = dormerName == BATCH_TYPE.TRIANGLE_DORMER ? 3 : 4
+ applyDormers(dormerParams, buttonAct)
+ } else {
+ let clonedObj = null
+
+ obj.clone((cloned) => {
+ clonedObj = cloned
+ clonedObj.fontSize = lengthTextFont.fontSize.value
+ })
+
+ addCanvasMouseEventListener('mouse:move', (e) => {
+ const pointer = canvas?.getPointer(e.e)
+ if (!clonedObj) return
+
+ canvas
+ .getObjects()
+ .filter((obj) => obj.name === 'clonedObj')
+ .forEach((obj) => canvas?.remove(obj))
+
+ clonedObj.set({
+ left: pointer.x,
+ top: pointer.y,
+ name: 'clonedObj',
+ })
+ canvas.add(clonedObj)
+ })
+
+ addCanvasMouseEventListener('mouse:down', (e) => {
+ clonedObj.set({
+ lockMovementX: true,
+ lockMovementY: true,
+ name: obj.name,
+ editable: false,
+ id: uuidv4(), //복사된 객체라 새로 따준다
+ })
+
+ //객체가 그룹일 경우에는 그룹 아이디를 따로 넣어준다
+ if (clonedObj.type === 'group') clonedObj.set({ groupId: uuidv4() })
+
+ //배치면일 경우
+ if (obj.name === 'roof') {
+ clonedObj.setCoords()
+ clonedObj.fire('modified')
+ clonedObj.fire('polygonMoved')
+ clonedObj.set({ direction: obj.direction, directionText: obj.directionText, roofMaterial: obj.roofMaterial })
+
+ obj.lines.forEach((line, index) => {
+ clonedObj.lines[index].set({ attributes: line.attributes })
+ })
+
+ canvas.renderAll()
+ addLengthText(clonedObj) //수치 추가
+ drawDirectionArrow(clonedObj) //방향 화살표 추가
+ }
+
+ initEvent()
+ })
+ }
}
}
diff --git a/src/hooks/common/useMasterController.js b/src/hooks/common/useMasterController.js
index e1c37915..60aab800 100644
--- a/src/hooks/common/useMasterController.js
+++ b/src/hooks/common/useMasterController.js
@@ -2,10 +2,6 @@ import { useAxios } from '@/hooks/useAxios'
import { useMessage } from '@/hooks/useMessage'
import { useSwal } from '@/hooks/useSwal'
import { getQueryString } from '@/util/common-utils'
-import { trestleRequest, constructionRequest, trestleDetailRequest } from '@/models/apiModels'
-import { POST } from '@/app/api/image-upload/route'
-import { canvasState } from '@/store/canvasAtom'
-import { useRecoilValue } from 'recoil'
/**
* 마스터 컨트롤러 훅
diff --git a/src/hooks/common/useMenu.js b/src/hooks/common/useMenu.js
index 84c8cef7..7fdd6a31 100644
--- a/src/hooks/common/useMenu.js
+++ b/src/hooks/common/useMenu.js
@@ -23,6 +23,10 @@ import { useTrestle } from '@/hooks/module/useTrestle'
import { usePolygon } from '@/hooks/usePolygon'
import { useOrientation } from '@/hooks/module/useOrientation'
+/**
+ * 메뉴 처리 훅
+ * @returns
+ */
export default function useMenu() {
const menus = []
const currentMenu = useRecoilValue(currentMenuState)
@@ -30,7 +34,7 @@ export default function useMenu() {
const [popupId, setPopupId] = useState(uuidv4())
const { addPopup } = usePopup()
const { deleteAllSurfacesAndObjects } = useSurfaceShapeBatch({})
- const { clear: trestleClear } = useTrestle()
+ const { clear: trestleClear, setAllModuleSurfaceIsComplete } = useTrestle()
const { nextStep } = useOrientation()
const handleMenu = (type) => {
if (type === 'outline') {
@@ -86,6 +90,7 @@ export default function useMenu() {
switch (currentMenu) {
case MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING:
trestleClear()
+ setAllModuleSurfaceIsComplete(false)
addPopup(popupId, 1, )
break
case MENU.MODULE_CIRCUIT_SETTING.CIRCUIT_TRESTLE_SETTING:
diff --git a/src/hooks/common/useRefFiles.js b/src/hooks/common/useRefFiles.js
index 71d2152c..b21cc954 100644
--- a/src/hooks/common/useRefFiles.js
+++ b/src/hooks/common/useRefFiles.js
@@ -1,12 +1,22 @@
import { useEffect, useRef, useState } from 'react'
-import { useRecoilState, useRecoilValue } from 'recoil'
+import { useRecoilState } from 'recoil'
import { useSwal } from '@/hooks/useSwal'
import { useAxios } from '../useAxios'
-import { canvasState, currentCanvasPlanState } from '@/store/canvasAtom'
-import { convertDwgToPng, removeImage, writeImageBuffer, readImage } from '@/lib/fileAction'
+import { currentCanvasPlanState } from '@/store/canvasAtom'
import { useCanvas } from '@/hooks/useCanvas'
+import { deleteBackGroundImage, setBackGroundImage } from '@/lib/imageActions'
+import { settingModalFirstOptionsState } from '@/store/settingAtom'
+/**
+ * 배경 이미지 관리
+ * 도면에 배경이미지를 로딩하는 기능을 제공
+ *
+ * 이미지 -> 캔버스 배경에 이미지 로드
+ * 주소 -> 구글 맵에서 주소 검색 후 이미지로 다운로드 받아서 캔버스 배경에 이미지 로드
+ * .dwg -> api를 통해서 .png로 변환 후 캔버스 배경에 이미지 로드
+ * @returns {object}
+ */
export function useRefFiles() {
const converterUrl = process.env.NEXT_PUBLIC_CONVERTER_API_URL
const [refImage, setRefImage] = useState(null)
@@ -15,33 +25,19 @@ export function useRefFiles() {
const [currentBgImage, setCurrentBgImage] = useState(null)
const queryRef = useRef(null)
const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
- // const canvas = useRecoilValue(canvasState)
- const { canvas, handleBackImageLoadToCanvas } = useCanvas()
+ const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState)
+ const { handleBackImageLoadToCanvas } = useCanvas()
const { swalFire } = useSwal()
- const { get, post, promisePost } = useAxios()
+ const { get, post } = useAxios()
useEffect(() => {
if (refFileMethod === '1') {
- // 파일 불러오기
setMapPositionAddress('')
} else {
setRefImage(null)
}
}, [refFileMethod])
- /**
- * 현재 플랜이 변경되면 플랜 상태 저장
- */
- useEffect(() => {
- // console.log('🚀 ~ useRefFiles ~ currentCanvasPlan:', currentCanvasPlan)
- // const handleCurrentPlan = async () => {
- // await promisePut({ url: '/api/canvas-management/canvas-statuses', data: currentCanvasPlan }).then((res) => {
- // console.log('🚀 ~ awaitpromisePut ~ res:', res)
- // })
- // }
- // handleCurrentPlan()
- }, [currentCanvasPlan])
-
/**
* 파일 불러오기 버튼 컨트롤
* @param {*} file
@@ -56,8 +52,6 @@ export function useRefFiles() {
type: 'confirm',
confirmFn: () => {
refFileSetting(file)
- // setRefImage(file)
- // file.name.split('.').pop() === 'dwg' ? handleUploadConvertRefFile(file) : handleUploadImageRefFile(file)
},
})
} else {
@@ -71,7 +65,6 @@ export function useRefFiles() {
handleUploadConvertRefFile(file)
} else {
if (file && ['image/png', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/gif'].includes(file.type)) {
- // file.name.split('.').pop() === 'dwg' ? handleUploadConvertRefFile(file) : handleUploadImageRefFile(file)
handleUploadImageRefFile(file)
} else {
swalFire({
@@ -82,19 +75,21 @@ export function useRefFiles() {
}
}
}
+
/**
* 파일 삭제
*/
- const handleFileDelete = () => {
+ const handleFileDelete = async () => {
swalFire({
text: '삭제하시겠습니까?',
type: 'confirm',
- confirmFn: () => {
+ confirmFn: async () => {
setRefImage(null)
setCurrentCanvasPlan((prev) => ({ ...prev, bgImageName: null }))
- // removeImage(currentCanvasPlan.id).then((res) => {
- // console.log(res)
- // })
+ await deleteBackGroundImage({
+ objectId: currentCanvasPlan.id,
+ planNo: currentCanvasPlan.planNo,
+ })
},
})
}
@@ -102,16 +97,18 @@ export function useRefFiles() {
/**
* 주소 삭제
*/
- const handleAddressDelete = () => {
+ const handleAddressDelete = async () => {
swalFire({
text: '삭제하시겠습니까?',
type: 'confirm',
- confirmFn: () => {
+ confirmFn: async () => {
setMapPositionAddress('')
+ setCurrentBgImage(null)
setCurrentCanvasPlan((prev) => ({ ...prev, mapPositionAddress: null }))
- // removeImage(currentCanvasPlan.id).then((res) => {
- // console.log(res)
- // })
+ await deleteBackGroundImage({
+ objectId: currentCanvasPlan.id,
+ planNo: currentCanvasPlan.planNo,
+ })
},
})
}
@@ -125,14 +122,27 @@ export function useRefFiles() {
return
}
+ const newOption1 = settingModalFirstOptions.option1.map((option) => ({
+ ...option,
+ selected: option.column === 'imageDisplay' ? true : option.selected,
+ }))
+
+ setSettingModalFirstOptions((prev) => ({
+ ...prev,
+ option1: newOption1,
+ }))
+
const res = await get({
url: `${process.env.NEXT_PUBLIC_HOST_URL}/map/convert?q=${queryRef.current.value}&fileNm=${currentCanvasPlan.id}&zoom=20`,
})
console.log('🚀 ~ handleMapImageDown ~ res:', res)
- // const file = await readImage(res.fileNm)
- // console.log('🚀 ~ handleMapImageDown ~ file:', file)
- // setCurrentBgImage(file)
setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`)
+
+ await setBackGroundImage({
+ objectId: currentCanvasPlan.id,
+ planNo: currentCanvasPlan.planNo,
+ imagePath: `${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`,
+ })
}
/**
@@ -143,7 +153,6 @@ export function useRefFiles() {
return
}
console.log('🚀 ~ useEffect ~ currentBgImage:', currentBgImage)
- // handleBackImageLoadToCanvas(`plan-images/${currentCanvasPlan.id}.png`)
handleBackImageLoadToCanvas(currentBgImage)
setCurrentCanvasPlan((prev) => ({
...prev,
@@ -157,20 +166,34 @@ export function useRefFiles() {
* @param {*} file
*/
const handleUploadImageRefFile = async (file) => {
+ const newOption1 = settingModalFirstOptions.option1.map((option) => ({
+ ...option,
+ selected: option.column === 'imageDisplay' ? true : option.selected,
+ }))
+
+ setSettingModalFirstOptions((prev) => ({
+ ...prev,
+ option1: newOption1,
+ }))
+
const formData = new FormData()
formData.append('file', file)
- // formData.append('fileName', currentCanvasPlan.id)
- // const res = await post({ url: `${process.env.NEXT_PUBLIC_API_SERVER_PATH}/api/image-upload`, data: formData })
const res = await post({
url: `${process.env.NEXT_PUBLIC_HOST_URL}/image/upload`,
data: formData,
})
console.log('🚀 ~ handleUploadImageRefFile ~ res:', res)
- // const image = await readImage(res.filePath)
- // console.log('🚀 ~ handleUploadImageRefFile ~ file:', image)
setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`)
setRefImage(file)
+
+ const params = {
+ objectId: currentCanvasPlan.id,
+ planNo: currentCanvasPlan.planNo,
+ imagePath: `${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`,
+ }
+ console.log('🚀 ~ handleUploadImageRefFile ~ params:', params)
+ await setBackGroundImage(params)
}
/**
@@ -190,15 +213,6 @@ export function useRefFiles() {
console.log('🚀 ~ handleUploadConvertRefFile ~ result:', result)
setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${result.filePath}`)
setRefImage(res.Files[0].FileData)
- // await promisePost({ url: converterUrl, data: formData })
- // .then((res) => {
- // convertDwgToPng(res.data.Files[0].FileName, res.data.Files[0].FileData)
- // swalFire({ text: '파일 변환 성공' })
- // setRefImage(res.data.Files[0].FileData)
- // })
- // .catch((err) => {
- // swalFire({ text: '파일 변환 실패', icon: 'error' })
- // })
}
/**
diff --git a/src/hooks/common/useRoofFn.js b/src/hooks/common/useRoofFn.js
index 3707af74..c49128e7 100644
--- a/src/hooks/common/useRoofFn.js
+++ b/src/hooks/common/useRoofFn.js
@@ -22,14 +22,7 @@ export function useRoofFn() {
const { addPitchText } = useLine()
//면형상 선택 클릭시 지붕 패턴 입히기
- function setSurfaceShapePattern(
- polygon,
- mode = 'onlyBorder',
- trestleMode = false,
- roofMaterial = selectedRoofMaterial,
- isForceChange = false,
- isDisplay = false,
- ) {
+ function setSurfaceShapePattern(polygon, mode = 'onlyBorder', trestleMode = false, roofMaterial, isForceChange = false, isDisplay = false) {
if (!polygon) {
return
}
@@ -41,6 +34,9 @@ export function useRoofFn() {
polygon.roofMaterial = null
}*/
}
+ if (!roofMaterial) {
+ roofMaterial = polygon.roofMaterial ?? selectedRoofMaterial
+ }
const ratio = window.devicePixelRatio || 1
const layout = roofMaterial.layout
diff --git a/src/hooks/floorPlan/estimate/useEstimateController.js b/src/hooks/floorPlan/estimate/useEstimateController.js
index b3c4c452..d509a1e0 100644
--- a/src/hooks/floorPlan/estimate/useEstimateController.js
+++ b/src/hooks/floorPlan/estimate/useEstimateController.js
@@ -83,6 +83,10 @@ export const useEstimateController = (planNo, flag) => {
res.data.pkgAsp = roundedNumber.toString()
}
setEstimateContextState(res.data)
+ } else {
+ swalFire({ text: getMessage('stuff.detail.header.notExistObjectNo'), type: 'alert', icon: 'error' })
+ setIsLoading(true)
+ setIsGlobalLoading(false)
}
}
})
@@ -90,8 +94,7 @@ export const useEstimateController = (planNo, flag) => {
setIsGlobalLoading(false)
} catch (error) {
console.error('견적서 상세조회 Error: ', error)
-
- swalFire({ text: getMessage('estimate.menu.move.valid1') })
+ swalFire({ text: getMessage('stuff.detail.header.notExistObjectNo'), type: 'alert', icon: 'error' })
setIsLoading(true)
setIsGlobalLoading(false)
}
@@ -126,6 +129,7 @@ export const useEstimateController = (planNo, flag) => {
delFlg: '0', //삭제 플래그 0 삭제하면 1
addFlg: true,
paDispOrder: null,
+ dispCableFlg: '0',
},
],
})
@@ -162,11 +166,6 @@ export const useEstimateController = (planNo, flag) => {
//견적서 저장
const handleEstimateSubmit = async () => {
- //todo: 추후 YJSS가 다시 나타날 경우 아래 swalFire 제거 필요
- if (estimateData.estimateType === 'YJSS') {
- return swalFire({ text: getMessage('estimate.detail.save.requiredEstimateType'), type: 'alert', icon: 'warning' })
- }
-
//0. 필수체크
let flag = true
let originFileFlg = false
@@ -295,6 +294,21 @@ export const useEstimateController = (planNo, flag) => {
}
}
}
+ } else {
+ if (item.salePrice === null) {
+ item.salePrice = '0'
+ } else if (isNaN(item.salePrice)) {
+ item.salePrice = '0'
+ }
+
+ if (item.unitPrice === null) {
+ item.unitPrice = '0'
+ } else if (isNaN(item.unitPrice)) {
+ item.unitPrice = '0'
+ }
+
+ //봄 컴포넌트 제품은 0으로
+ item.openFlg = '0'
}
}
})
@@ -379,6 +393,7 @@ export const useEstimateController = (planNo, flag) => {
estimateData.estimateOption = estimateOptions
// console.log('최종아이템:::', estimateData.itemList)
+
if (fileList?.length > 0) {
estimateData.fileList = fileList
} else {
@@ -406,7 +421,7 @@ export const useEstimateController = (planNo, flag) => {
})
} catch (e) {
setIsGlobalLoading(false)
- console.log('error::::::::::::', e.response.data.message)
+ console.error('error::::::::::::', e.response.data.message)
}
}
@@ -415,11 +430,7 @@ export const useEstimateController = (planNo, flag) => {
* (견적서 번호(estimateData.docNo)가 생성된 이후 버튼 활성화 )
* T01관리자 계정 및 1차판매점에게만 제공
*/
- const handleEstimateCopy = async (sendPlanNo, copyReceiveUser, saleStoreId, otherSaleStoreId) => {
- //todo: 추후 YJSS가 다시 나타날 경우 아래 swalFire 제거 필요
- if (estimateData.estimateType === 'YJSS') {
- return swalFire({ text: getMessage('estimate.detail.save.requiredEstimateType'), type: 'alert', icon: 'warning' })
- }
+ const handleEstimateCopy = async (sendPlanNo, copyReceiveUser, saleStoreId, otherSaleStoreId, setEstimateCopyPopupOpen) => {
if (saleStoreId === '') {
return swalFire({
text: getMessage('estimate.detail.productFeaturesPopup.requiredStoreId'),
@@ -434,7 +445,12 @@ export const useEstimateController = (planNo, flag) => {
type: 'alert',
icon: 'warning',
})
+ } else {
+ if (checkLength(copyReceiveUser.trim()) > 10) {
+ return swalFire({ text: getMessage('stuff.detail.tempSave.message2'), type: 'alert', icon: 'warning' })
+ }
}
+
const params = {
saleStoreId: session.storeId,
sapSalesStoreCd: session.custCd,
@@ -445,7 +461,9 @@ export const useEstimateController = (planNo, flag) => {
userId: session.userId,
}
+ setIsGlobalLoading(true)
await promisePost({ url: '/api/estimate/save-estimate-copy', data: params }).then((res) => {
+ setIsGlobalLoading(false)
if (res.status === 201) {
if (isObjectNotEmpty(res.data)) {
let newObjectNo = res.data.objectNo
@@ -453,14 +471,33 @@ export const useEstimateController = (planNo, flag) => {
text: getMessage('estimate.detail.estimateCopyPopup.copy.alertMessage'),
type: 'alert',
confirmFn: () => {
+ setEstimateCopyPopupOpen(false) //팝업닫고
router.push(`/management/stuff/detail?objectNo=${newObjectNo.toString()}`, { scroll: false })
},
})
}
+ } else {
+ setIsGlobalLoading(false)
}
})
}
+ const checkLength = (value) => {
+ let str = new String(value)
+ let _byte = 0
+ if (str.length !== 0) {
+ for (let i = 0; i < str.length; i++) {
+ let str2 = str.charAt(i)
+ if (encodeURIComponent(str2).length > 4) {
+ _byte += 2
+ } else {
+ _byte++
+ }
+ }
+ }
+ return _byte
+ }
+
return {
estimateContextState,
setEstimateContextState,
diff --git a/src/hooks/floorPlan/useImgLoader.js b/src/hooks/floorPlan/useImgLoader.js
index 15fdd2f7..e51a4a2b 100644
--- a/src/hooks/floorPlan/useImgLoader.js
+++ b/src/hooks/floorPlan/useImgLoader.js
@@ -1,6 +1,5 @@
import { useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom'
-import { useCanvas } from '../useCanvas'
import { useAxios } from '../useAxios'
import { usePlan } from '../usePlan'
import { POLYGON_TYPE } from '@/common/common'
@@ -9,6 +8,8 @@ import { useContext } from 'react'
/**
* 이미지 로더 hook
+ * 캔버스를 바이너리로 변환하고 이미지 객체에 붙여서 다시 이미지를 바이너리로 전달
+ * 캔버스 데이터가 바이너리로 변경되면 용량이 너무 커서 post전송에 실패할 수 있음
* @returns {function} handleCanvasToPng
*/
export function useImgLoader() {
@@ -67,7 +68,7 @@ export function useImgLoader() {
formData.append('objectNo', currentCanvasPlan.objectNo)
formData.append('planNo', currentCanvasPlan.planNo)
formData.append('type', type)
- // formData.append('coordinates', getImageCoordinates())
+ /** 이미지 크롭 좌표 계산 */
const positionObj = getImageCoordinates()
console.log('🚀 ~ handleCanvasToPng ~ positionObj:', positionObj)
formData.append('width', Math.round(positionObj[1].x - positionObj[0].x + 100))
@@ -76,7 +77,7 @@ export function useImgLoader() {
formData.append('top', Math.round(positionObj[0].y))
console.log('🚀 ~ handleCanvasToPng ~ formData:', formData)
- // 이미지 크롭 요청
+ /** 이미지 크롭 요청 */
const result = await post({
url: `${process.env.NEXT_PUBLIC_HOST_URL}/image/canvas`,
data: formData,
diff --git a/src/hooks/main/useMainContentsController.js b/src/hooks/main/useMainContentsController.js
index 01f75658..f065c90f 100644
--- a/src/hooks/main/useMainContentsController.js
+++ b/src/hooks/main/useMainContentsController.js
@@ -4,29 +4,24 @@ import { useContext, useEffect } from 'react'
import { useAxios } from '../useAxios'
import { SessionContext } from '@/app/SessionProvider'
import { QcastContext } from '@/app/QcastProvider'
+import { checkSession } from '@/lib/authActions'
+import { useRouter } from 'next/navigation'
export const useMainContentsController = () => {
const { session } = useContext(SessionContext)
const { promiseGet } = useAxios()
const { setQcastState, setIsGlobalLoading } = useContext(QcastContext)
+ const router = useRouter()
useEffect(() => {
+ checkSession().then((res) => {
+ if (!res) {
+ router.replace('/login', undefined, { shallow: true })
+ }
+ })
setIsGlobalLoading(true)
}, [])
- /**
- * main search area
- */
- // const [saleStoreId, setSaleStoreId] = useState('')
- // const [saleStoreName, setSaleStoreName] = useState('')
-
- /**
- * main contents area
- */
- // const [objectList, setObjectList] = useState([])
- // const [businessCharger, setBusinessCharger] = useState(null)
- // const [businessChargerMail, setBusinessChargerMail] = useState(null)
-
/**
* 최근 물건 목록 조회
*/
@@ -37,12 +32,6 @@ export const useMainContentsController = () => {
url: apiUrl,
}).then((res) => {
if (res.status === 200) {
- // setSaleStoreId(res.data.saleStoreId)
- // setSaleStoreName(res.data.saleStoreName)
-
- // setObjectList(res.data.objectList)
- // setBusinessCharger(res.data.businessCharger)
- // setBusinessChargerMail(res.data.businessChargerMail)
setQcastState({
saleStoreId: res.data.saleStoreId,
saleStoreName: res.data.saleStoreName,
@@ -52,12 +41,6 @@ export const useMainContentsController = () => {
})
setIsGlobalLoading(false)
} else {
- // setSaleStoreId('')
- // setSaleStoreName('')
-
- // setObjectList([])
- // setBusinessCharger(null)
- // setBusinessChargerMail(null)
setQcastState({
saleStoreId: '',
saleStoreName: '',
@@ -65,9 +48,11 @@ export const useMainContentsController = () => {
businessCharger: null,
businessChargerMail: null,
})
+ setIsGlobalLoading(false)
}
})
} catch (error) {
+ setIsGlobalLoading(false)
console.error('MAIN API fetching error:', error)
}
}
@@ -83,11 +68,6 @@ export const useMainContentsController = () => {
}
return {
- // saleStoreId,
- // saleStoreName,
- // objectList,
- // businessCharger,
- // businessChargerMail,
fetchObjectList,
initObjectList,
}
diff --git a/src/hooks/module/useModule.js b/src/hooks/module/useModule.js
index bd462b5e..51cffd65 100644
--- a/src/hooks/module/useModule.js
+++ b/src/hooks/module/useModule.js
@@ -1,4 +1,4 @@
-import { BATCH_TYPE, POLYGON_TYPE } from '@/common/common'
+import { BATCH_TYPE, POLYGON_TYPE, TRESTLE_MATERIAL } from '@/common/common'
import { canvasState } from '@/store/canvasAtom'
import { isOverlap, polygonToTurfPolygon, rectToPolygon } from '@/util/canvas-util'
import { useRecoilValue, useSetRecoilState } from 'recoil'
@@ -10,6 +10,7 @@ import { useMessage } from '../useMessage'
import { selectedModuleState } from '@/store/selectedModuleOptions'
import { moduleStatisticsState } from '@/store/circuitTrestleAtom'
import { useCircuitTrestle } from '../useCirCuitTrestle'
+import { useTrestle } from './useTrestle'
export const MODULE_REMOVE_TYPE = {
LEFT: 'left',
@@ -39,20 +40,25 @@ export function useModule() {
const { getMessage } = useMessage()
const { checkModuleDisjointObjects } = useModuleBasicSetting()
const selectedModules = useRecoilValue(selectedModuleState)
- const { setModuleStatisticsData } = useCircuitTrestle()
+ const { setModuleStatisticsData, resetCircuits } = useCircuitTrestle()
+ const { clear: removeTrestleMaterials } = useTrestle()
const moduleMove = (length, direction) => {
const selectedObj = canvas.getActiveObjects() //선택된 객체들을 가져옴
const selectedIds = selectedObj.map((obj) => obj.id) // selectedObj의 ID 추출
-
+ if (selectedObj[0].circuit) {
+ swalFire({
+ title: getMessage('can.not.move.module'),
+ icon: 'error',
+ type: 'alert',
+ })
+ return
+ }
canvas.discardActiveObject() //선택해제
- debugger
const isSetupModules = getOtherModules(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 setupSurface = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === selectedModules[0].surfaceId)
let isWarning = false
const objects = getObjects()
@@ -101,13 +107,24 @@ export function useModule() {
canvas.discardActiveObject()
return
}
- const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
+ const activeModule = canvas.getObjects().find((obj) => canvas.getActiveObjects()[0].id === obj.id)
+ const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
+ if (activeModule.circuit) {
+ if (surfaces.some((surface) => surface.isComplete)) {
+ swalFire({
+ title: getMessage('can.not.move.module'),
+ icon: 'error',
+ type: 'alert',
+ })
+ return
+ }
+
+ removeTrestleMaterials()
+ }
const modules = type === 'row' ? getRowModules(activeModule) : getColumnModules(activeModule)
const otherModules = getOtherModules(modules)
const objects = getObjects()
- const moduleSetupSurface = canvas
- .getObjects()
- .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0]
+ const moduleSetupSurface = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)
let isWarning = false
modules.forEach((module) => {
@@ -122,11 +139,9 @@ export function useModule() {
module.setCoords()
canvas.renderAll()
- if (otherModules.length > 0) {
- if (isOverlapOtherModules(module, otherModules) || isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) {
- isWarning = true
- module.set({ fill: 'red' })
- }
+ if (isOverlapOtherModules(module, otherModules) || isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) {
+ isWarning = true
+ module.set({ fill: 'red' })
}
})
@@ -214,7 +229,7 @@ export function useModule() {
}
modules.forEach((module) => {
- const { top, left } = getPosotion(module, direction, Number(length) + Number(moduleLength), false)
+ const { top, left } = getPosotion(module, direction, Number(length) + Number(moduleLength) * 10, false)
module.clone((obj) => {
obj.set({
parentId: module.parentId,
@@ -226,6 +241,7 @@ export function useModule() {
length: module.length,
points: module.points,
surfaceId: module.surfaceId,
+ moduleInfo: module.moduleInfo,
left,
top,
id: uuidv4(),
@@ -252,8 +268,12 @@ export function useModule() {
canvas.renderAll()
},
})
+ } else {
+ surface.set({ modules: [...surface.modules, ...copyModules] })
}
})
+
+ setModuleStatisticsData()
}
const moduleCopy = (length, direction) => {
@@ -262,9 +282,7 @@ export function useModule() {
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]
+ const moduleSetupSurface = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === modules[0].surfaceId)
let isWarning = false
let copyModules = []
let copyModule = null
@@ -282,6 +300,7 @@ export function useModule() {
length: module.length,
points: module.points,
surfaceId: module.surfaceId,
+ moduleInfo: module.moduleInfo,
left,
top,
id: uuidv4(),
@@ -330,15 +349,26 @@ export function useModule() {
canvas.discardActiveObject()
return
}
- const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
+ const activeModule = canvas.getObjects().find((obj) => canvas.getActiveObjects()[0].id === obj.id)
+ if (activeModule.circuit) {
+ const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
+ if (surfaces.some((surface) => surface.isComplete)) {
+ swalFire({
+ title: getMessage('can.not.copy.module'),
+ icon: 'error',
+ type: 'alert',
+ })
+ return
+ }
+
+ removeTrestleMaterials()
+ }
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 copyModules = []
let copyModule = null
- const moduleSetupSurface = canvas
- .getObjects()
- .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === modules[0].surfaceId)[0]
+ const moduleSetupSurface = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === modules[0].surfaceId)
let isWarning = false
let moduleLength = 0
if (['up', 'down'].includes(direction)) {
@@ -348,7 +378,7 @@ export function useModule() {
}
modules.forEach((module) => {
- const { top, left } = getPosotion(module, direction, Number(length) + Number(moduleLength), false)
+ const { top, left } = getPosotion(module, direction, Number(length), true)
module.clone((obj) => {
obj.set({
parentId: module.parentId,
@@ -359,6 +389,7 @@ export function useModule() {
type: module.type,
length: module.length,
points: module.points,
+ moduleInfo: module.moduleInfo,
surfaceId: module.surfaceId,
left,
top,
@@ -368,6 +399,7 @@ export function useModule() {
canvas.add(obj)
copyModules.push(obj)
obj.setCoords()
+ console.log(obj)
})
if (
isOverlapOtherModules(copyModule, otherModules) ||
@@ -397,7 +429,10 @@ export function useModule() {
}
const moduleColumnRemove = (type) => {
- const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
+ if (isFixedModule()) {
+ return
+ }
+ const activeModule = canvas.getObjects().find((obj) => canvas.getActiveObjects()[0].id === obj.id)
const columnModules = getColumnModules(activeModule)
const otherModules = getOtherModules(columnModules)
const objects = getObjects()
@@ -405,10 +440,15 @@ export function useModule() {
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]
+ const moduleSetupSurface = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)
let isWarning = false
+ if (moduleSetupSurface.isComplete) {
+ resetSurface()
+ }
+ const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
+ if (surfaces.some((surface) => surface.isComplete)) {
+ removeTrestleMaterials()
+ }
canvas.discardActiveObject()
moduleSetupSurface.set({ modules: otherModules })
canvas.remove(...columnModules)
@@ -499,6 +539,7 @@ export function useModule() {
icon: 'error',
type: 'alert',
confirmFn: () => {
+ moduleSetupSurface.modules = [...moduleSetupSurface.modules, ...columnModules]
canvas.add(...columnModules)
targetModules.forEach((module) => {
module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
@@ -507,12 +548,16 @@ export function useModule() {
canvas.renderAll()
},
})
+ } else {
+ moduleSetupSurface.modules = moduleSetupSurface.modules.filter(
+ (module) => !columnModules.map((copyModule) => copyModule.id).includes(module.id),
+ )
}
setModuleStatisticsData()
}
const moduleRowRemove = (type) => {
- const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
+ const activeModule = canvas.getObjects().find((obj) => canvas.getActiveObjects()[0].id === obj.id)
const rowModules = getRowModules(activeModule)
const otherModules = getOtherModules(rowModules)
const objects = getObjects()
@@ -520,11 +565,12 @@ export function useModule() {
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]
+ const moduleSetupSurface = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)
let isWarning = false
-
+ const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
+ if (surfaces.some((surface) => surface.isComplete)) {
+ removeTrestleMaterials()
+ }
canvas.discardActiveObject()
moduleSetupSurface.set({ modules: otherModules })
canvas.remove(...rowModules)
@@ -615,6 +661,7 @@ export function useModule() {
icon: 'error',
type: 'alert',
confirmFn: () => {
+ moduleSetupSurface.modules = [...moduleSetupSurface.modules, ...rowModules]
canvas.add(...rowModules)
targetModules.forEach((module) => {
module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
@@ -628,7 +675,7 @@ export function useModule() {
}
const moduleColumnInsert = (type) => {
- const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
+ const activeModule = canvas.getObjects().find((obj) => canvas.getActiveObjects()[0].id === obj.id)
const columnModules = getColumnModules(activeModule)
let otherModules = getOtherModules(columnModules)
const targetModules =
@@ -637,24 +684,12 @@ export function useModule() {
: otherModules.filter((module) => module.left > activeModule.left).sort((a, b) => a.left - b.left)
const objects = getObjects()
const copyModules = []
- const moduleSetupSurface = canvas
- .getObjects()
- .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0]
- let width = -1
+ const moduleSetupSurface = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)
let isWarning = false
- if (targetModules.length === 0) {
- swalFire({
- title: '마지막 모듈입니다.',
- icon: 'error',
- type: 'alert',
- })
- return
- }
+ const { moduleIntvlHor, moduleIntvlVer } = moduleSetupSurface.trestleDetail
canvas.discardActiveObject()
targetModules.forEach((module) => {
- if (width === -1)
- width = type === MODULE_INSERT_TYPE.LEFT ? Number(activeModule.left) - Number(module.left) : Number(module.left) - Number(activeModule.left)
- const { top, left } = getPosotion(module, type, module.width, false)
+ const { top, left } = getPosotion(module, type, moduleIntvlHor, true)
module.originPos = {
left: module.left,
top: module.top,
@@ -671,7 +706,7 @@ export function useModule() {
canvas.renderAll()
otherModules = getOtherModules(columnModules)
columnModules.forEach((module) => {
- const { top, left } = getPosotion(module, type, module.width, false)
+ const { top, left } = getPosotion(module, type, moduleIntvlHor, true)
let copyModule = null
module.clone((obj) => {
obj.set({
@@ -683,6 +718,7 @@ export function useModule() {
type: module.type,
length: module.length,
points: module.points,
+ moduleInfo: module.moduleInfo,
surfaceId: module.surfaceId,
left,
top,
@@ -701,6 +737,7 @@ export function useModule() {
isOutsideSurface(copyModule, moduleSetupSurface)
) {
isWarning = true
+ copyModule.set({ fill: 'red' })
}
module.setCoords()
})
@@ -719,38 +756,46 @@ export function useModule() {
canvas.renderAll()
},
})
+ } else {
+ moduleSetupSurface.modules = [...moduleSetupSurface.modules, ...copyModules]
}
setModuleStatisticsData()
}
+ const isFixedModule = () => {
+ const completeSurfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.isComplete)
+
+ if (completeSurfaces.length > 0) {
+ swalFire({
+ title: getMessage('modal.module.can.not.edit'),
+ type: 'alert',
+ icon: 'error',
+ })
+ return true
+ }
+
+ return false
+ }
+
const muduleRowInsert = (type) => {
- const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
+ if (isFixedModule()) {
+ return
+ }
+ const activeModule = canvas.getObjects().find((obj) => canvas.getActiveObjects()[0].id === obj.id)
const rowModules = getRowModules(activeModule)
let otherModules = getOtherModules(rowModules)
const targetModules =
type === MODULE_INSERT_TYPE.TOP
? otherModules.filter((module) => module.top < activeModule.top).sort((a, b) => a.top - b.top)
: otherModules.filter((module) => module.top > activeModule.top).sort((a, b) => a.top - b.top)
- if (targetModules.length === 0) {
- swalFire({
- title: '마지막 모듈입니다.',
- icon: 'error',
- type: 'alert',
- })
- return
- }
const objects = getObjects()
const copyModules = []
- const moduleSetupSurface = canvas
- .getObjects()
- .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0]
- let height = -1
+ 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
canvas.discardActiveObject()
targetModules.forEach((module) => {
- if (height === -1)
- height = type === MODULE_INSERT_TYPE.TOP ? Number(activeModule.top) - Number(module.top) : Number(module.top) - Number(activeModule.top)
- const { top, left } = getPosotion(module, type, activeModule.height, false)
+ const { top, left } = getPosotion(module, type, moduleIntvlVer, true)
module.originPos = {
left: module.left,
top: module.top,
@@ -766,7 +811,7 @@ export function useModule() {
canvas.renderAll()
otherModules = getOtherModules(rowModules)
rowModules.forEach((module) => {
- const { top, left } = getPosotion(module, type, activeModule.height, false)
+ const { top, left } = getPosotion(module, type, moduleIntvlVer, true)
let copyModule = null
module.clone((obj) => {
obj.set({
@@ -779,6 +824,7 @@ export function useModule() {
length: module.length,
points: module.points,
surfaceId: module.surfaceId,
+ moduleInfo: module.moduleInfo,
fill: module.fill,
left,
top,
@@ -817,16 +863,15 @@ export function useModule() {
canvas.renderAll()
},
})
+ } else {
+ moduleSetupSurface.modules = [...moduleSetupSurface.modules, ...copyModules]
}
setModuleStatisticsData()
}
const alignModule = (type, surfaceArray) => {
surfaceArray.forEach((surface) => {
- const modules = canvas
- .getObjects()
- .filter((module) => module.name === POLYGON_TYPE.MODULE)
- .filter((module) => module.surfaceId === surface.id)
+ const modules = surface.modules
const objects = getObjects()
let [top, bottom, left, right] = [0, 0, 0, 0]
@@ -882,8 +927,16 @@ export function useModule() {
})
}
+ // 회로가 없을때만 삭제 가능
const modulesRemove = () => {
- const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
+ const activeModule = canvas.getObjects().find((obj) => canvas.getActiveObjects()[0].id === obj.id)
+ const modules = canvas
+ .getObjects()
+ .filter((obj) => obj.surfaceId === activeModule.surfaceId && obj.name === POLYGON_TYPE.MODULE && activeModule.id !== obj.id)
+ const surface = canvas.getObjects().find((obj) => obj.id === activeModule.surfaceId && obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
+ if (surface.isComplete) {
+ removeTrestleMaterials()
+ }
if (activeModule.circuit) {
swalFire({
title: getMessage('can.not.remove.module'),
@@ -892,10 +945,7 @@ export function useModule() {
})
return
}
- const modules = canvas
- .getObjects()
- .filter((obj) => obj.surfaceId === activeModule.surfaceId && obj.name === POLYGON_TYPE.MODULE && activeModule.id !== obj.id)
- const surface = canvas.getObjects().filter((obj) => obj.id === activeModule.surfaceId && obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)[0]
+
surface.set({ modules: modules })
canvas.remove(activeModule)
canvas.renderAll()
@@ -909,13 +959,17 @@ export function useModule() {
.getObjects()
.filter((module) => module.name === POLYGON_TYPE.MODULE && module.surfaceId === surface.id)
.forEach((module) => {
+ canvas.remove(module.circuit)
canvas.remove(module)
})
})
+ canvas.renderAll()
setModuleStatisticsData()
}
const isOverlapOtherModules = (module, otherModules) => {
+ if (otherModules.length === 0) return false
+
return otherModules.some(
(otherModule) =>
turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(otherModule, true)) ||
@@ -953,16 +1007,16 @@ export function useModule() {
let left = target.left
if (direction === 'up') {
- top = Number(target.top) - Number(length)
+ top = Number(target.top) - Number(length) / 10
top = hasMargin ? top - Number(target.height) : top
} else if (direction === 'down') {
- top = Number(target.top) + Number(length)
+ top = Number(target.top) + Number(length) / 10
top = hasMargin ? top + Number(target.height) : top
} else if (direction === 'left') {
- left = Number(target.left) - Number(length)
+ left = Number(target.left) - Number(length) / 10
left = hasMargin ? left - Number(target.width) : left
} else if (direction === 'right') {
- left = Number(target.left) + Number(length)
+ left = Number(target.left) + Number(length) / 10
left = hasMargin ? left + Number(target.width) : left
}
return { top, left }
@@ -981,6 +1035,11 @@ export function useModule() {
.filter((obj) => [BATCH_TYPE.OPENING, BATCH_TYPE.TRIANGLE_DORMER, BATCH_TYPE.PENTAGON_DORMER, BATCH_TYPE.SHADOW].includes(obj.name))
}
+ const resetSurface = () => {
+ resetCircuits()
+ removeTrestleMaterials()
+ }
+
return {
moduleMove,
moduleMultiMove,
diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js
index 74158c1f..5db1963e 100644
--- a/src/hooks/module/useModuleBasicSetting.js
+++ b/src/hooks/module/useModuleBasicSetting.js
@@ -1,13 +1,13 @@
import { useState } from 'react'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { canvasSettingState, canvasState, checkedModuleState, currentObjectState, isManualModuleSetupState } from '@/store/canvasAtom'
-import { rectToPolygon, polygonToTurfPolygon, calculateVisibleModuleHeight, getDegreeByChon } from '@/util/canvas-util'
-import { addedRoofsState, basicSettingState, roofDisplaySelector } from '@/store/settingAtom'
-import offsetPolygon, { calculateAngle } from '@/util/qpolygon-utils'
+import { rectToPolygon, polygonToTurfPolygon, calculateVisibleModuleHeight, getDegreeByChon, toFixedWithoutRounding } from '@/util/canvas-util'
+import { basicSettingState, roofDisplaySelector } from '@/store/settingAtom'
+import offsetPolygon, { calculateAngle, createLinesFromPolygon } from '@/util/qpolygon-utils'
import { QPolygon } from '@/components/fabric/QPolygon'
import { moduleSetupSurfaceState, moduleIsSetupState } from '@/store/canvasAtom'
import { useEvent } from '@/hooks/useEvent'
-import { POLYGON_TYPE, BATCH_TYPE } from '@/common/common'
+import { POLYGON_TYPE, BATCH_TYPE, LINE_TYPE } from '@/common/common'
import * as turf from '@turf/turf'
import { useSwal } from '@/hooks/useSwal'
import { compasDegAtom } from '@/store/orientationAtom'
@@ -19,23 +19,20 @@ import { moduleStatisticsState } from '@/store/circuitTrestleAtom'
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { useMasterController } from '@/hooks/common/useMasterController'
import { v4 as uuidv4 } from 'uuid'
-// import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle'
import { isObjectNotEmpty } from '@/util/common-utils'
import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle'
+import { useMode } from '@/hooks/useMode'
export function useModuleBasicSetting(tabNum) {
const canvas = useRecoilValue(canvasState)
const { getMessage } = useMessage()
const roofDisplay = useRecoilValue(roofDisplaySelector)
const [moduleSetupSurface, setModuleSetupSurface] = useRecoilState(moduleSetupSurfaceState)
- const [moduleIsSetup, setModuleIsSetup] = useRecoilState(moduleIsSetupState)
const { addCanvasMouseEventListener, initEvent, removeMouseEvent, addTargetMouseEventListener } = useEvent()
- // const { setModuleStatisticsData } = useCircuitTrestle()
const { swalFire } = useSwal()
const compasDeg = useRecoilValue(compasDegAtom)
const { setSurfaceShapePattern } = useRoofFn()
- const [basicSetting, setBasicSettings] = useRecoilState(basicSettingState)
const checkedModule = useRecoilValue(checkedModuleState)
const [isManualModuleSetup, setIsManualModuleSetup] = useRecoilState(isManualModuleSetupState)
const setModuleStatistics = useSetRecoilState(moduleStatisticsState)
@@ -51,6 +48,7 @@ export function useModuleBasicSetting(tabNum) {
const [currentObject, setCurrentObject] = useRecoilState(currentObjectState)
const { setModuleStatisticsData } = useCircuitTrestle()
+ const { createRoofPolygon, createMarginPolygon, createPaddingPolygon } = useMode()
useEffect(() => {
// console.log('basicSetting', basicSetting)
@@ -60,6 +58,13 @@ export function useModuleBasicSetting(tabNum) {
// canvas.selection = true
// canvas.selectionFullyContained = true
}
+
+ return () => {
+ //수동 설치시 초기화
+ removeMouseEvent('mouse:up')
+ removeMouseEvent('mouse:move')
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tempModule')) //움직일때 일단 지워가면서 움직임
+ }
}, [])
// const { addTargetMouseEventListener, addCanvasMouseEventListener, initEvent } = useContext(EventContext)
@@ -71,13 +76,10 @@ export function useModuleBasicSetting(tabNum) {
const common = moduleSelectionData.common
const roofConstructions = moduleSelectionData.roofConstructions
- // console.log('roofConstructions', roofConstructions)
-
if (roofConstructions && roofConstructions.length > 0) {
const listParams = roofConstructions.map((item) => {
return {
...common,
- // moduleTpCd: selectedModules.itemTp,
roofMatlCd: item.trestle.roofMatlCd,
trestleMkrCd: item.trestle.trestleMkrCd,
constMthdCd: item.trestle.constMthdCd,
@@ -109,9 +111,6 @@ export function useModuleBasicSetting(tabNum) {
}
}
}
- // console.log('moduleSelectionData', moduleSelectionData)
-
- // console.log('canvasSetting.roofSizeSet', canvasSetting.roofSizeSet)
//가대 상세 데이터 조회
const getTrestleDetailListData = async () => {
@@ -131,6 +130,7 @@ export function useModuleBasicSetting(tabNum) {
//가대 상세 데이터 들어오면 실행
useEffect(() => {
if (trestleDetailList.length > 0) {
+ console.log('trestleDetailList', trestleDetailList)
//지붕을 가져옴
canvas
.getObjects()
@@ -143,6 +143,12 @@ export function useModuleBasicSetting(tabNum) {
if (Number(detail.data.roofIndex) === roofIndex) {
//roof에 상세 데이터 추가
roof.set({ trestleDetail: detail.data })
+ roof.lines.forEach((line) => {
+ line.attributes = {
+ ...line.attributes,
+ offset: getOffset(detail.data, line.attributes.type),
+ }
+ })
//배치면 설치 영역
makeModuleInstArea(roof, detail.data)
//surface에 상세 데이터 추가
@@ -153,6 +159,19 @@ export function useModuleBasicSetting(tabNum) {
}
}, [trestleDetailList])
+ const getOffset = (data, type) => {
+ switch (type) {
+ case LINE_TYPE.WALLLINE.EAVES:
+ return data.eaveIntvl / 10
+ case LINE_TYPE.WALLLINE.GABLE:
+ return data.kerabaIntvl / 10
+ case LINE_TYPE.SUBLINE.RIDGE:
+ case LINE_TYPE.WALLLINE.SHED:
+ return data.ridgeIntvl / 10
+ default:
+ return 200 / 10
+ }
+ }
//선택 배치면 배열`
let selectedModuleInstSurfaceArray = []
@@ -218,15 +237,36 @@ export function useModuleBasicSetting(tabNum) {
toggleSelection(isExistSurface)
})
} else {
- let offsetLength = canvasSetting.roofSizeSet === '3' ? -30 : (trestleDetail.eaveIntvl / 10) * -1
setSurfaceShapePattern(roof, roofDisplay.column, true, roof.roofMaterial) //패턴 변경
- const offsetPoints = offsetPolygon(roof.points, offsetLength) //안쪽 offset
+ // let offsetPoints = createPaddingPolygon(createRoofPolygon(roof.points), roof.lines).vertices //안쪽 offset
+ let offsetPoints = null
+ console.log(roof, roof.getCurrentPoints())
+ const polygon = createRoofPolygon(roof.getCurrentPoints())
+ const originPolygon = new QPolygon(roof.getCurrentPoints(), { fontSize: 0 })
+
+ let result = createPaddingPolygon(polygon, roof.lines).vertices
+
+ //margin polygon 의 point가 기준 polygon의 밖에 있는지 판단한다.
+ const allPointsOutside = result.every((point) => !originPolygon.inPolygon(point))
+
+ if (canvasSetting.roofSizeSet == '3') {
+ //육지붕일때는 그냥 하드코딩
+ offsetPoints = offsetPolygon(roof.points, -30) //육지붕일때
+ } else {
+ //육지붕이 아닐때
+ if (allPointsOutside) {
+ offsetPoints = createMarginPolygon(polygon, roof.lines).vertices
+ } else {
+ offsetPoints = createPaddingPolygon(polygon, roof.lines).vertices
+ }
+ }
+
//모듈설치영역?? 생성
const surfaceId = uuidv4()
let isNorth = false
- if (canvasSetting.roofSizeSet !== '3') {
+ if (canvasSetting.roofSizeSet != '3') {
//북면이 있지만
if (roof.directionText && roof.directionText.indexOf('北') > -1) {
//북쪽일때 해당 서북서, 동북동은 제외한다고 한다
@@ -325,8 +365,6 @@ export function useModuleBasicSetting(tabNum) {
canvas?.renderAll()
selectedModuleInstSurfaceArray.push(setupSurface)
- // console.log('selectedModuleInstSurfaceArray', selectedModuleInstSurfaceArray)
-
setCurrentObject({ name: 'moduleSetupSurface', arrayData: [...selectedModuleInstSurfaceArray] })
} else {
//선택후 재선택하면 선택안됨으로 변경
@@ -353,11 +391,11 @@ export function useModuleBasicSetting(tabNum) {
//모듈,회로에서 다른메뉴 -> 배치면으로 갈 경수 초기화
const restoreModuleInstArea = () => {
//설치면 삭제
- const setupArea = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
+ const setupArea = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE || obj.name === POLYGON_TYPE.OBJECT_SURFACE)
//모듈 삭제 및 초기화
setupArea.forEach((obj) => {
- if (obj.modules.length > 0) {
+ if (isObjectNotEmpty(obj.modules) && obj.modules.length > 0) {
obj.modules.forEach((module) => {
canvas.remove(module)
})
@@ -369,7 +407,7 @@ export function useModuleBasicSetting(tabNum) {
//지붕패턴 변경
const roofs = canvas.getObjects().filter((obj) => obj.name === 'roof')
roofs.forEach((roof) => {
- setSurfaceShapePattern(roof, roofDisplay.column, false) //패턴 변경
+ setSurfaceShapePattern(roof, roofDisplay.column, false, roof.roofMaterial) //패턴 변경
})
}
@@ -385,8 +423,9 @@ export function useModuleBasicSetting(tabNum) {
* trestle에서 영역을 가져와 mouse:move 이벤트로 해당 영역에 진입했을때 booleanPointInPolygon 로 진입여부를 확인
* 확인 후 셀을 이동시킴
*/
- const manualModuleSetup = () => {
- // console.log('isManualModuleSetup', isManualModuleSetup)
+ const manualModuleSetup = (placementRef) => {
+ console.log('isManualModuleSetup', isManualModuleSetup)
+
const moduleSetupSurfaces = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) //모듈설치면를 가져옴
if (isManualModuleSetup) {
@@ -411,10 +450,11 @@ export function useModuleBasicSetting(tabNum) {
})
})
+ //모듈 기본 옵션
const moduleOptions = {
fill: checkedModule[0].color,
stroke: 'black',
- strokeWidth: 0.1,
+ strokeWidth: 0.3,
selectable: true, // 선택 가능하게 설정
lockMovementX: true, // X 축 이동 잠금
lockMovementY: true, // Y 축 이동 잠금
@@ -437,6 +477,7 @@ export function useModuleBasicSetting(tabNum) {
const mousePoint = canvas.getPointer(e.e)
for (let i = 0; i < moduleSetupSurfaces.length; i++) {
+ //배치면이 여러개 일때 옮겨가면서 동작해야함
turfPolygon = polygonToTurfPolygon(moduleSetupSurfaces[i])
trestlePolygon = moduleSetupSurfaces[i]
manualDrawModules = moduleSetupSurfaces[i].modules // 앞에서 자동으로 했을때 추가됨
@@ -448,15 +489,27 @@ export function useModuleBasicSetting(tabNum) {
let tmpHeight = flowDirection === 'south' || flowDirection === 'north' ? moduleHeight : moduleWidth
let { width, height } =
- canvasSetting.roofSizeSet === '1'
+ canvasSetting.roofSizeSet == '1'
? calculateVisibleModuleHeight(tmpWidth, tmpHeight, getDegreeByChon(moduleSetupSurfaces[i].roofMaterial.pitch), flowDirection)
: { width: tmpWidth, height: tmpHeight }
const points = [
- { x: mousePoint.x - width / 2, y: mousePoint.y - height / 2 },
- { x: mousePoint.x + width / 2, y: mousePoint.y - height / 2 },
- { x: mousePoint.x + width / 2, y: mousePoint.y + height / 2 },
- { x: mousePoint.x - width / 2, y: mousePoint.y + height / 2 },
+ {
+ x: toFixedWithoutRounding(mousePoint.x, 2) + toFixedWithoutRounding(width / 2, 2),
+ y: toFixedWithoutRounding(mousePoint.y, 2) - toFixedWithoutRounding(height / 2, 2),
+ },
+ {
+ x: toFixedWithoutRounding(mousePoint.x, 2) + toFixedWithoutRounding(width / 2, 2),
+ y: toFixedWithoutRounding(mousePoint.y, 2) + toFixedWithoutRounding(height / 2, 2),
+ },
+ {
+ x: toFixedWithoutRounding(mousePoint.x, 2) - toFixedWithoutRounding(width / 2, 2),
+ y: toFixedWithoutRounding(mousePoint.y, 2) - toFixedWithoutRounding(height / 2, 2),
+ },
+ {
+ x: toFixedWithoutRounding(mousePoint.x, 2) - toFixedWithoutRounding(width / 2, 2),
+ y: toFixedWithoutRounding(mousePoint.y, 2) + toFixedWithoutRounding(height / 2, 2),
+ },
]
const turfPoints = coordToTurfPolygon(points)
@@ -471,10 +524,10 @@ export function useModuleBasicSetting(tabNum) {
fill: 'white',
stroke: 'black',
strokeWidth: 0.3,
- width: width,
- height: height,
- left: mousePoint.x - width / 2,
- top: mousePoint.y - height / 2,
+ width: toFixedWithoutRounding(width, 2),
+ height: toFixedWithoutRounding(height, 2),
+ left: toFixedWithoutRounding(mousePoint.x, 2) - toFixedWithoutRounding(width / 2, 2),
+ top: toFixedWithoutRounding(mousePoint.y, 2) - toFixedWithoutRounding(height / 2, 2),
selectable: false,
lockMovementX: true,
lockMovementY: true,
@@ -495,8 +548,8 @@ export function useModuleBasicSetting(tabNum) {
/**
* 스냅기능
*/
- let snapDistance = 80
- let cellSnapDistance = 20
+ let snapDistance = flowDirection === 'south' || flowDirection === 'north' ? 70 : 40
+ let trestleSnapDistance = 15
let intvHor =
flowDirection === 'south' || flowDirection === 'north'
@@ -507,67 +560,84 @@ export function useModuleBasicSetting(tabNum) {
? moduleSetupSurfaces[i].trestleDetail.moduleIntvlVer / 10
: moduleSetupSurfaces[i].trestleDetail.moduleIntvlHor / 10
- const trestleLeft = moduleSetupSurfaces[i].left
- const trestleTop = moduleSetupSurfaces[i].top
- const trestleRight = trestleLeft + moduleSetupSurfaces[i].width * moduleSetupSurfaces[i].scaleX
- const trestleBottom = trestleTop + moduleSetupSurfaces[i].height * moduleSetupSurfaces[i].scaleY
+ const trestleLeft = toFixedWithoutRounding(moduleSetupSurfaces[i].left, 2) - toFixedWithoutRounding(moduleSetupSurfaces[i].width / 2, 2)
+ const trestleTop = toFixedWithoutRounding(moduleSetupSurfaces[i].top, 2) - toFixedWithoutRounding(moduleSetupSurfaces[i].height / 2, 2)
+ const trestleRight =
+ toFixedWithoutRounding(moduleSetupSurfaces[i].left, 2) + toFixedWithoutRounding(moduleSetupSurfaces[i].width / 2, 2)
+ const trestleBottom =
+ toFixedWithoutRounding(moduleSetupSurfaces[i].top, 2) + toFixedWithoutRounding(moduleSetupSurfaces[i].height / 2, 2)
const bigCenterY = (trestleTop + trestleTop + moduleSetupSurfaces[i].height) / 2
- // 작은 폴리곤의 경계 좌표 계산
- const smallLeft = tempModule.left
- const smallTop = tempModule.top
- const smallRight = smallLeft + tempModule.width * tempModule.scaleX
- const smallBottom = smallTop + tempModule.height * tempModule.scaleY
- const smallCenterX = smallLeft + (tempModule.width * tempModule.scaleX) / 2
- const smallCenterY = smallTop + (tempModule.height * tempModule.scaleX) / 2
+ // 이동하는 모듈의 경계 좌표
+ const smallLeft = toFixedWithoutRounding(tempModule.left, 2)
+ const smallTop = toFixedWithoutRounding(tempModule.top, 2)
+ const smallRight = smallLeft + toFixedWithoutRounding(tempModule.width, 2)
+ const smallBottom = smallTop + toFixedWithoutRounding(tempModule.height, 2)
+ const smallCenterX = smallLeft + toFixedWithoutRounding(tempModule.width / 2, 2)
+ const smallCenterY = smallTop + toFixedWithoutRounding(tempModule.height / 2, 2)
/**
* 미리 깔아놓은 셀이 있을때 셀에 흡착됨
*/
if (manualDrawModules) {
manualDrawModules.forEach((cell) => {
- const holdCellLeft = cell.left
- const holdCellTop = cell.top
- const holdCellRight = holdCellLeft + cell.width * cell.scaleX
- const holdCellBottom = holdCellTop + cell.height * cell.scaleY
- const holdCellCenterX = holdCellLeft + (cell.width * cell.scaleX) / 2
- const holdCellCenterY = holdCellTop + (cell.height * cell.scaleY) / 2
+ const holdCellLeft = toFixedWithoutRounding(cell.left, 2)
+ const holdCellTop = toFixedWithoutRounding(cell.top, 2)
+ const holdCellRight = holdCellLeft + toFixedWithoutRounding(cell.width, 2)
+ const holdCellBottom = holdCellTop + toFixedWithoutRounding(cell.height, 2)
+ const holdCellCenterX = holdCellLeft + toFixedWithoutRounding(cell.width / 2, 2)
+ const holdCellCenterY = holdCellTop + toFixedWithoutRounding(cell.height / 2, 2)
+
+ //가운데 -> 가운대
+ if (Math.abs(smallCenterX - holdCellCenterX) < snapDistance) {
+ tempModule.left = holdCellCenterX - toFixedWithoutRounding(width / 2, 2)
+ }
+
+ //왼쪽 -> 가운데
+ if (Math.abs(smallLeft - holdCellCenterX) < snapDistance) {
+ // console.log('holdCellCenterX', holdCellCenterX)
+ // console.log('smallLeft', smallLeft)
+
+ // console.log('모듈 센터에 스냅')
+ tempModule.left = holdCellCenterX + intvHor / 2
+
+ // console.log('tempModule.left', tempModule.left)
+ }
+ // 오른쪽 -> 가운데
+ if (Math.abs(smallRight - holdCellCenterX) < snapDistance) {
+ tempModule.left = holdCellCenterX - width - intvHor / 2
+ }
//설치된 셀에 좌측에 스냅
if (Math.abs(smallRight - holdCellLeft) < snapDistance) {
+ // console.log('모듈 좌측 스냅')
tempModule.left = holdCellLeft - width - intvHor
}
//설치된 셀에 우측에 스냅
if (Math.abs(smallLeft - holdCellRight) < snapDistance) {
+ // console.log('모듈 우측 스냅')
tempModule.left = holdCellRight + intvHor
}
-
//설치된 셀에 위쪽에 스냅
- if (Math.abs(smallBottom - holdCellTop) < snapDistance) {
+ if (Math.abs(smallBottom - holdCellTop) < 10) {
tempModule.top = holdCellTop - height - intvVer
}
//설치된 셀에 밑쪽에 스냅
- if (Math.abs(smallTop - holdCellBottom) < snapDistance) {
+ if (Math.abs(smallTop - holdCellBottom) < 10) {
tempModule.top = holdCellBottom + intvVer
}
- //가운데 -> 가운데
- if (Math.abs(smallCenterX - holdCellCenterX) < cellSnapDistance) {
- tempModule.left = holdCellCenterX - width / 2
- }
- //왼쪽 -> 가운데
- if (Math.abs(smallLeft - holdCellCenterX) < cellSnapDistance) {
- tempModule.left = holdCellCenterX
- }
- // 오른쪽 -> 가운데
- if (Math.abs(smallRight - holdCellCenterX) < cellSnapDistance) {
- tempModule.left = holdCellCenterX - width
+
+ //설치된 셀에 윗쪽에 스냅
+ if (Math.abs(smallTop - holdCellTop) < 10) {
+ tempModule.top = holdCellTop
}
+
//세로 가운데 -> 가운데
- if (Math.abs(smallCenterY - holdCellCenterY) < cellSnapDistance) {
- tempModule.top = holdCellCenterY - height / 2
- }
+ // if (Math.abs(smallCenterY - holdCellCenterY) < snapDistance) {
+ // tempModule.top = holdCellCenterY - toFixedWithoutRounding(height / 2, 1)
+ // }
// //위쪽 -> 가운데
// if (Math.abs(smallTop - holdCellCenterY) < cellSnapDistance) {
// tempModule.top = holdCellCenterY
@@ -579,54 +649,54 @@ export function useModuleBasicSetting(tabNum) {
})
}
- // // 위쪽 변에 스냅
- // if (Math.abs(smallTop - trestleTop) < snapDistance) {
- // tempModule.top = trestleTop
- // }
+ // 위쪽 변에 스냅
+ if (Math.abs(smallTop - trestleTop) < trestleSnapDistance) {
+ tempModule.top = trestleTop + 1
+ }
- // // 아래쪽 변에 스냅
- // if (Math.abs(smallTop + tempModule.height * tempModule.scaleY - (trestleTop + moduleSetupSurfaces[i].height)) < snapDistance) {
- // tempModule.top = trestleTop + moduleSetupSurfaces[i].height - tempModule.height * tempModule.scaleY
- // }
+ // 아래쪽 변에 스냅
+ if (Math.abs(smallBottom - trestleBottom) < trestleSnapDistance) {
+ tempModule.top = trestleTop + moduleSetupSurfaces[i].height - tempModule.height - 1
+ }
- // // 왼쪽변에 스냅
- // if (Math.abs(smallLeft - trestleLeft) < snapDistance) {
- // tempModule.left = trestleLeft
- // }
- // //오른쪽 변에 스냅
- // if (Math.abs(smallRight - trestleRight) < snapDistance) {
- // tempModule.left = trestleRight - tempModule.width * tempModule.scaleX
- // }
+ // 왼쪽변에 스냅
+ if (Math.abs(smallLeft - trestleLeft) < trestleSnapDistance) {
+ tempModule.left = trestleLeft + 1
+ }
+ //오른쪽 변에 스냅
+ if (Math.abs(smallRight - trestleRight) < trestleSnapDistance) {
+ tempModule.left = trestleRight - tempModule.width - 1
+ }
- // if (flowDirection === 'south' || flowDirection === 'north') {
- // // 모듈왼쪽이 세로중앙선에 붙게 스냅
- // if (Math.abs(smallLeft - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < snapDistance) {
- // tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2
- // }
+ if (flowDirection === 'south' || flowDirection === 'north') {
+ // 모듈왼쪽이 세로중앙선에 붙게 스냅
+ // if (Math.abs(smallLeft - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < snapDistance) {
+ // tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2
+ // }
- // // 모듈이 가운데가 세로중앙선에 붙게 스냅
- // if (Math.abs(smallCenterX - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < snapDistance) {
- // tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - (tempModule.width * tempModule.scaleX) / 2
- // }
+ // 모듈이 가운데가 세로중앙선에 붙게 스냅
+ if (Math.abs(smallCenterX - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < trestleSnapDistance) {
+ tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - tempModule.width / 2
+ }
- // // 모듈오른쪽이 세로중앙선에 붙게 스냅
- // if (Math.abs(smallRight - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < snapDistance) {
- // tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - tempModule.width * tempModule.scaleX
- // }
- // } else {
- // // 모듈이 가로중앙선에 스냅
- // if (Math.abs(smallTop + tempModule.height / 2 - bigCenterY) < snapDistance) {
- // tempModule.top = bigCenterY - tempModule.height / 2
- // }
+ // 모듈오른쪽이 세로중앙선에 붙게 스냅
+ // if (Math.abs(smallRight - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < trestleSnapDistance) {
+ // tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - tempModule.width * tempModule.scaleX
+ // }
+ } else {
+ // 모듈이 가로중앙선에 스냅
+ if (Math.abs(smallTop + tempModule.height / 2 - bigCenterY) < trestleSnapDistance) {
+ tempModule.top = bigCenterY - tempModule.height / 2
+ }
- // if (Math.abs(smallTop - (trestleTop + moduleSetupSurfaces[i].height / 2)) < snapDistance) {
- // tempModule.top = trestleTop + moduleSetupSurfaces[i].height / 2
- // }
- // // 모듈 밑면이 가로중앙선에 스냅
- // if (Math.abs(smallBottom - (trestleTop + moduleSetupSurfaces[i].height / 2)) < snapDistance) {
- // tempModule.top = trestleTop + moduleSetupSurfaces[i].height / 2 - tempModule.height * tempModule.scaleY
- // }
- // }
+ // if (Math.abs(smallTop - (trestleTop + moduleSetupSurfaces[i].height / 2)) < trestleSnapDistance) {
+ // tempModule.top = trestleTop + moduleSetupSurfaces[i].height / 2
+ // }
+ // 모듈 밑면이 가로중앙선에 스냅
+ // if (Math.abs(smallBottom - (trestleTop + moduleSetupSurfaces[i].height / 2)) < trestleSnapDistance) {
+ // tempModule.top = trestleTop + moduleSetupSurfaces[i].height / 2 - tempModule.height * tempModule.scaleY
+ // }
+ }
tempModule.setCoords()
canvas?.renderAll()
@@ -649,13 +719,19 @@ export function useModuleBasicSetting(tabNum) {
if (!inside) return
if (tempModule) {
const rectPoints = [
- { x: tempModule.left, y: tempModule.top },
- { x: tempModule.left + tempModule.width * tempModule.scaleX, y: tempModule.top },
+ { x: toFixedWithoutRounding(tempModule.left, 2), y: toFixedWithoutRounding(tempModule.top, 2) },
{
- x: tempModule.left + tempModule.width * tempModule.scaleX,
- y: tempModule.top + tempModule.height * tempModule.scaleY,
+ x: toFixedWithoutRounding(tempModule.left, 2) + toFixedWithoutRounding(tempModule.width, 2),
+ y: toFixedWithoutRounding(tempModule.top, 2),
+ },
+ {
+ x: toFixedWithoutRounding(tempModule.left, 2) + toFixedWithoutRounding(tempModule.width, 2),
+ y: toFixedWithoutRounding(tempModule.top, 2) + toFixedWithoutRounding(tempModule.height, 2),
+ },
+ {
+ x: toFixedWithoutRounding(tempModule.left, 2),
+ y: toFixedWithoutRounding(tempModule.top, 2) + toFixedWithoutRounding(tempModule.height, 2),
},
- { x: tempModule.left, y: tempModule.top + tempModule.height * tempModule.scaleY },
]
tempModule.set({ points: rectPoints })
@@ -679,7 +755,7 @@ export function useModuleBasicSetting(tabNum) {
tempModule.setCoords() //좌표 재정렬
if (turf.booleanContains(turfPolygon, tempTurfModule) || turf.booleanWithin(tempTurfModule, turfPolygon)) {
//마우스 클릭시 set으로 해당 위치에 셀을 넣음
- const isOverlap = manualDrawModules.some((module) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(module))) //겹치는지 확인
+ const isOverlap = manualDrawModules.some((module) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(module, true))) //겹치는지 확인
if (!isOverlap) {
canvas?.remove(tempModule)
@@ -687,11 +763,22 @@ export function useModuleBasicSetting(tabNum) {
// tempModule.setCoords()
moduleOptions.surfaceId = trestlePolygon.id
- let manualModule = new QPolygon(tempModule.points, { ...moduleOptions, moduleInfo: checkedModule[0] })
+ // console.log('tempModule.points', tempModule.points)
+
+ let manualModule = new QPolygon(tempModule.points, {
+ ...moduleOptions,
+ moduleInfo: checkedModule[0],
+ left: toFixedWithoutRounding(tempModule.left, 2),
+ top: toFixedWithoutRounding(tempModule.top, 2),
+ width: toFixedWithoutRounding(tempModule.width, 2),
+ height: toFixedWithoutRounding(tempModule.height, 2),
+ toFixed: 2,
+ })
+
canvas?.add(manualModule)
manualDrawModules.push(manualModule)
setModuleStatisticsData()
- getModuleStatistics()
+ // getModuleStatistics()
} else {
swalFire({ text: getMessage('module.place.overlab') })
}
@@ -842,6 +929,7 @@ export function useModuleBasicSetting(tabNum) {
return turf.booleanContains(turfModuleSetupSurface, squarePolygon) || turf.booleanWithin(squarePolygon, turfModuleSetupSurface)
}
+ //흐름 방향이 남쪽(아래)
const downFlowSetupModule = (
surfaceMaxLines,
maxLengthLine,
@@ -854,69 +942,95 @@ export function useModuleBasicSetting(tabNum) {
) => {
let setupModule = []
- checkedModule.forEach((module, index) => {
- const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
+ const trestleDetailData = moduleSetupSurface.trestleDetail
+ const moduleMaxCols = trestleDetailData.moduleMaxCols // 모듈 최대 가로 설치 갯수
- const flowLines = getFlowLines(moduleSetupSurface, height)
- //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음
- // let startPoint = flowLines.bottom
+ let installedLastHeightCoord = 0 //마지막으로 설치된 모듈의 좌표
+ let installedModuleHeightCount = 0 //마지막으로 설치된 모듈의 카운트
+ let isChidoriLine = false
+ let flowLines
- let startPoint = flowLines.bottom
- const moduleArray = []
+ checkedModule.forEach((module, moduleIndex) => {
+ const tmpModuleData = trestleDetailData.module.filter((moduleObj) => module.moduleTpCd === moduleObj.moduleTpCd)[0]
+ //혼합모듈일때는 mixModuleMaxRows 값이 0 이상임
+ let moduleMaxRows = tmpModuleData.mixModuleMaxRows === 0 ? tmpModuleData.moduleMaxRows : tmpModuleData.mixModuleMaxRows
- console.log('flowLines', flowLines)
+ //모듈의 넓이 높이를 가져옴 (복시도 촌수 적용)
+ //1번 깔았던 모듈 기준으로 잡야아함
+ let { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
- if (isCenter) {
- //중앙배치일 경우에는 계산한다
- if (flowLines.bottom.type === 'flat' && flowLines.left.type === 'flat' && flowLines.right.type === 'flat') {
- //하단 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치
- const halfWidthLength = Math.abs(startPoint.x1 + startPoint.x2) / 2 //밑에 길이에서 반을 가른다
- const halfModuleWidthLength = width / 2
- startPoint = { ...startPoint, x1: halfWidthLength - halfModuleWidthLength }
-
- if (flowLines.top.type === 'flat') {
- //상단까지 평면이면 직사각,정사각이라 가정하고 상자의 중심으로 계산
- const heightLength = Math.abs(flowLines.left.y1 - flowLines.left.y2) //옆에에 길이에서 반을 가른다
- const heightMargin = Math.abs(heightLength - height * Math.floor(heightLength / height)) / 2
- startPoint = { ...startPoint, y1: startPoint.y1 - heightMargin }
- }
+ if (moduleIndex === 0) {
+ flowLines = getFlowLines(moduleSetupSurface, height)
+ if (flowLines.bottom.type === 'curve') {
+ flowLines = getFlowLines(moduleSetupSurface, width)
}
}
- //밑에가 평면이면 좌측으로 붙여서 배치
- // if (flowLines.bottom.type === 'flat' && flowLines.left.type === 'curve') {
- // startPoint = flowLines.left
- // }
- const maxLeftEndPoint = surfaceMaxLines.left.x1 //최 좌측
- const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측
- const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단
+ //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음
+ const moduleArray = []
- let totalLeftEndPoint = maxLeftEndPoint - startPoint.x1
- let totalTopEndPoint = maxTopEndPoint - startPoint.y1
- let totalWidth = Math.ceil(Math.abs(maxRightEndPoint - maxLeftEndPoint) / width)
- let diffLeftEndPoint = Math.abs(totalLeftEndPoint / width)
- let diffTopEndPoint = Math.abs(totalTopEndPoint / height)
- let startColPoint = Math.abs(width * Math.ceil(diffLeftEndPoint) - startPoint.x1)
- let tempMaxWidth = isMaxSetup ? width / 2 : width //최대배치인지 확인하려고 넣음
- if (isMaxSetup) totalWidth = totalWidth * 2 //최대배치시 2배로 늘려서 반씩 검사하기위함
+ let calcAreaWidth = Math.abs(flowLines.right.x1 - flowLines.left.x1) //오른쪽 x에서 왼쪽 x를 뺀 가운데를 찾는 로직
+ let calcModuleWidthCount = calcAreaWidth / (width + intvHor + 1) //뺀 공간에서 모듈을 몇개를 넣을수 있는지 확인하는 로직
- for (let j = 0; j < diffTopEndPoint; j++) {
- bottomMargin = j === 0 ? 0 : intvVer * j
- for (let i = 0; i <= totalWidth; i++) {
- leftMargin = i === 0 ? 0 : intvHor * i
- chidoriLength = 0
+ let calcMaxModuleWidthCount = calcModuleWidthCount > moduleMaxCols ? moduleMaxCols : calcModuleWidthCount //최대 모듈 단수가 있기 때문에 최대 단수보다 카운트가 크면 최대 단수로 씀씀
+ let totalModuleWidthCount = Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다
+
+ let calcAreaHeight = flowLines.bottom.y1 - flowLines.top.y1
+ let calcModuleHeightCount = calcAreaHeight / (height + intvVer + 1)
+
+ let calcStartPoint = flowLines.right.type === 'flat' ? (calcAreaWidth - totalModuleWidthCount * width) / 2 : 0 //반씩 나눠서 중앙에 맞춤 bottom 기준으로 양변이 직선일때만 가운데 정렬
+ let startPointX = flowLines.left.x1 + calcStartPoint //시작점을 만든다
+
+ //근데 양변이 곡선이면 중앙에 맞추기 위해 아래와 위의 길이를 재서 모듈의 길이를 나눠서 들어갈수 있는 갯수가 동일하면 가운데로 정렬 시킨다
+ if (flowLines.left.type === 'curve' && flowLines.right.type === 'curve') {
+ startPointX = isChidori ? flowLines.left.x1 + 1 : flowLines.left.x1 + (calcAreaWidth - totalModuleWidthCount * width) / 2
+ }
+
+ let heightMargin = 0
+ let widthMargin = 0
+ let chidoriLength = 0
+
+ //첫번재 모듈 설치 후 두번째 모듈을 몇개까지 설치 할 수 있는지 계산
+ if (moduleIndex > 0) {
+ // moduleMaxRows = totalModuleMaxRows - installedModuleHeightCount //두번째 모듈일때
+ isChidoriLine = installedModuleHeightCount % 2 != 0 ? true : false //첫번째에서 짝수에서 끝났으면 홀수는 치도리가 아님 짝수는 치도리
+ }
+
+ for (let i = 0; i < calcModuleHeightCount; i++) {
+ let isInstall = false
+ let moduleY = flowLines.bottom.y1 - height * i - 1 //살짝 여유를 준다
+
+ //두번째 모듈 -> 혼합일 경우의 설치될 모듈 높이를 계산
+ if (moduleIndex > 0) {
+ moduleY = installedLastHeightCoord - intvVer
+ }
+
+ //첫번째는 붙여서 두번째는 마진을 주고 설치
+ heightMargin = i === 0 ? 0 : intvVer * i
+
+ for (let j = 0; j < totalModuleWidthCount; j++) {
+ let moduleX = startPointX + width * j + 1 //5정도 마진을 준다
+ widthMargin = j === 0 ? 0 : intvHor * j // 가로 마진값
+ chidoriLength = 0 //치도리가 아니여도 기본값을 5정도 준다
if (isChidori && !isMaxSetup) {
- chidoriLength = j % 2 === 0 ? 0 : width / 2 - intvHor
+ chidoriLength = installedModuleHeightCount % 2 == 0 ? 0 : width / 2 - intvHor
}
- square = [
- [startColPoint + tempMaxWidth * i - chidoriLength + leftMargin, startPoint.y1 - height * j - bottomMargin],
- [startColPoint + tempMaxWidth * i + width - chidoriLength + leftMargin, startPoint.y1 - height * j - bottomMargin],
- [startColPoint + tempMaxWidth * i + width - chidoriLength + leftMargin, startPoint.y1 - height * j - height - bottomMargin],
- [startColPoint + tempMaxWidth * i - chidoriLength + leftMargin, startPoint.y1 - height * j - height - bottomMargin],
- [startColPoint + tempMaxWidth * i - chidoriLength + leftMargin, startPoint.y1 - height * j - bottomMargin],
+ //치도리 일때 는 짝수(1 기준) 일때만 치도리 라인으로 본다
+ if (isChidori && isChidoriLine) {
+ chidoriLength = width / 2 - intvHor
+ }
+
+ let square = [
+ [moduleX + widthMargin + chidoriLength, moduleY - height - heightMargin],
+ [moduleX + widthMargin + chidoriLength, moduleY - heightMargin],
+ [moduleX + width + widthMargin + chidoriLength, moduleY - heightMargin],
+ [moduleX + width + widthMargin + chidoriLength, moduleY - height - heightMargin],
+ [moduleX + widthMargin + chidoriLength, moduleY - height - heightMargin],
]
+ // console.log('square', square)
+
let squarePolygon = turf.polygon([square])
let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1)
let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] }))
@@ -928,148 +1042,30 @@ export function useModuleBasicSetting(tabNum) {
let isDisjoint = checkModuleDisjointObjects(squarePolygon, containsBatchObjects)
if (disjointFromTrestle && isDisjoint) {
- if (index > 0) {
- setupModule.forEach((item) => {
- const isOverlap = item.some((item2) => turf.booleanOverlap(squarePolygon, polygonToTurfPolygon(item2, true)))
- if (!isOverlap) {
- canvas?.add(tempModule)
- moduleSetupArray.push(tempModule)
- moduleArray.push(tempModule)
- canvas.renderAll()
- }
- })
- } else {
- //최초 한번은 그냥 그린다
- //겹치는지 확인해서 포함된 모듈만 그린다
- canvas?.add(tempModule)
- moduleSetupArray.push(tempModule)
- moduleArray.push(tempModule)
- canvas.renderAll()
- }
+ //최초 한번은 그냥 그린다
+ //겹치는지 확인해서 포함된 모듈만 그린다
+ canvas?.add(tempModule)
+ moduleSetupArray.push(tempModule)
+ moduleArray.push(tempModule)
+ canvas.renderAll()
+
+ // ++installedModuleHeightCount
+
+ isInstall = true
+ //마지막에 설치된 모듈의 Y 좌표
+ installedLastHeightCoord = moduleY - height - heightMargin
} else {
//디버깅용
- // tempModule.set({ fill: 'rgba(255,190,41, 0.4)', stroke: 'black', strokeWidth: 1 })
+ // tempModule.set({ fill: 'transparent', stroke: 'red', strokeWidth: 1 })
// canvas?.add(tempModule)
// canvas.renderAll()
}
}
- }
-
- setupModule.push(moduleArray)
- })
- }
-
- const leftFlowSetupModule = (
- surfaceMaxLines,
- maxLengthLine,
- moduleSetupArray,
- moduleSetupSurface,
- containsBatchObjects,
- isCenter = false,
- intvHor,
- intvVer,
- ) => {
- let setupModule = []
-
- checkedModule.forEach((module, index) => {
- const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
- let flowLines = getFlowLines(moduleSetupSurface, width)
- //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음
- let startPoint = flowLines.left
- const moduleArray = []
-
- // if (flowLines.left.type === 'flat') {
- // const tempPoint = { ...flowLines.top }
- // startPoint = { ...flowLines.top, x1: tempPoint.x2, x2: tempPoint.x1 }
- // } else {
- // flowLines = getFlowLines(moduleSetupSurface, height)
- // const tempPoint = { ...flowLines.left }
- // startPoint = { ...flowLines.left, x1: tempPoint.x1 + 5, x2: tempPoint.x2, y1: tempPoint.y1 - 5 }
- // }
-
- //중앙배치일 경우에는 계산한다
- if (isCenter) {
- if (flowLines.left.type === 'flat' && flowLines.bottom.type === 'flat' && flowLines.top.type === 'flat') {
- //좌측 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치
- const halfWidthLength = Math.abs(startPoint.y1 + startPoint.y2) / 2 //밑에 길이에서 반을 가른다
- const halfModuleWidthLength = height / 2
- startPoint = { ...startPoint, y1: halfWidthLength - halfModuleWidthLength }
- if (flowLines.right.type === 'flat') {
- //우측까지 평면이면 직사각,정사각이라 가정하고 상자의 중심으로 계산
- const widthLength = Math.abs(flowLines.top.x1 - flowLines.top.x2) //옆에에 길이에서 반을 가른다
- const widthMargin = Math.abs(widthLength - width * Math.floor(widthLength / width)) / 2
- startPoint = { ...startPoint, x1: startPoint.x1 + widthMargin }
- }
+ if (isInstall) {
+ ++installedModuleHeightCount
}
}
- const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측
- const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단
- const maxBottomEndPoint = surfaceMaxLines.bottom.y1 //최하단
-
- let totalTopEndPoint = Math.abs(maxTopEndPoint - startPoint.y1) //전체 높이에서 현재 높이를 뺌
- let diffTopEndPoint = Math.abs(totalTopEndPoint / height)
- let totalHeight = Math.ceil(Math.abs(maxBottomEndPoint - maxTopEndPoint) / height)
- let totalWidth = Math.abs(startPoint.x1 - maxRightEndPoint) / width
- let startRowPoint = startPoint.y1 - height * Math.ceil(diffTopEndPoint)
-
- let tempMaxHeight = isMaxSetup ? height / 2 : height //최대배치인지 확인하려고 넣음
- if (isMaxSetup) totalHeight = totalHeight * 2 //최대배치시 2배로 늘려 서 반씩 검사
-
- for (let i = 0; i <= totalWidth; i++) {
- bottomMargin = i === 0 ? 0 : intvHor * i
- for (let j = 0; j < totalHeight; j++) {
- leftMargin = j === 0 ? 0 : intvVer * j
- chidoriLength = 0
- if (isChidori && !isMaxSetup) {
- chidoriLength = i % 2 === 0 ? 0 : height / 2
- }
-
- square = [
- [startPoint.x1 + width * i + bottomMargin, startRowPoint + tempMaxHeight * j + leftMargin - chidoriLength],
- [startPoint.x1 + width * i + width + bottomMargin, startRowPoint + tempMaxHeight * j + leftMargin - chidoriLength],
- [startPoint.x1 + width * i + width + bottomMargin, startRowPoint + tempMaxHeight * j + height + leftMargin - chidoriLength],
- [startPoint.x1 + width * i + bottomMargin, startRowPoint + tempMaxHeight * j + height + leftMargin - chidoriLength],
- [startPoint.x1 + width * i + bottomMargin, startRowPoint + tempMaxHeight * j + leftMargin - chidoriLength],
- ]
-
- let squarePolygon = turf.polygon([square])
- let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1)
- let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] }))
-
- // if (disjointFromTrestle && isDisjoint) {
- moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id, moduleInfo: module }
- let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon })
- let disjointFromTrestle = checkModuleDisjointSurface(squarePolygon, polygonToTurfPolygon(moduleSetupSurface, true))
- let isDisjoint = checkModuleDisjointObjects(squarePolygon, containsBatchObjects)
-
- if (disjointFromTrestle && isDisjoint) {
- if (index > 0) {
- setupModule.forEach((item) => {
- const isOverlap = item.some((item2) => turf.booleanOverlap(squarePolygon, polygonToTurfPolygon(item2, true)))
- if (!isOverlap) {
- canvas?.add(tempModule)
- moduleSetupArray.push(tempModule)
- moduleArray.push(tempModule)
- canvas.renderAll()
- }
- })
- } else {
- //최초 한번은 그냥 그린다
- //겹치는지 확인해서 포함된 모듈만 그린다
- canvas?.add(tempModule)
- moduleSetupArray.push(tempModule)
- moduleArray.push(tempModule)
- canvas.renderAll()
- }
- } else {
- //디버깅용
- // tempModule.set({ fill: 'rgba(255,190,41, 0.4)', stroke: 'black', strokeWidth: 1 })
- // canvas?.add(tempModule)
- // canvas.renderAll()
- }
- }
- }
setupModule.push(moduleArray)
})
}
@@ -1086,81 +1082,95 @@ export function useModuleBasicSetting(tabNum) {
) => {
let setupModule = []
- checkedModule.forEach((module, index) => {
+ const trestleDetailData = moduleSetupSurface.trestleDetail
+ const moduleMaxCols = trestleDetailData.moduleMaxCols // 모듈 최대 가로 설치 갯수
+
+ let installedLastHeightCoord = 0 //마지막으로 설치된 모듈의 좌표
+ let installedModuleHeightCount = 0 //마지막으로 설치된 모듈의 카운트
+ let isChidoriLine = false
+ let flowLines
+
+ checkedModule.forEach((module, moduleIndex) => {
+ const tmpModuleData = trestleDetailData.module.filter((moduleObj) => module.moduleTpCd === moduleObj.moduleTpCd)[0]
+ //혼합모듈일때는 mixModuleMaxRows 값이 0 이상임
+ let moduleMaxRows = tmpModuleData.mixModuleMaxRows === 0 ? tmpModuleData.moduleMaxRows : tmpModuleData.mixModuleMaxRows
+ // 혼합모듈 포함 총 모듈 설치 높이 갯수
+ const totalModuleMaxRows = tmpModuleData.moduleMaxRows
+
const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
- const flowLines = getFlowLines(moduleSetupSurface, height)
- let startPoint = flowLines.top
- // if (flowLines.top.type === 'flat' && flowLines.right.type === 'curve') {
- // startPoint = flowLines.right
- // }
-
- const moduleArray = []
-
- if (isCenter) {
- //중앙배치일 경우에는 계산한다
- if (flowLines.top.type === 'flat' && flowLines.left.type === 'flat' && flowLines.right.type === 'flat') {
- //하단 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치
- const halfWidthLength = Math.abs(startPoint.x1 + startPoint.x2) / 2 //밑에 길이에서 반을 가른다
- const halfModuleWidthLength = width / 2
- startPoint = { ...startPoint, x1: halfWidthLength - halfModuleWidthLength }
-
- if (flowLines.bottom.type === 'flat') {
- //상단까지 평면이면 직사각,정사각이라 가정하고 상자의 중심으로 계산
- const heightLength = Math.abs(flowLines.left.y1 - flowLines.left.y2) //옆에에 길이에서 반을 가른다
- const heightMargin = Math.abs(heightLength - height * Math.floor(heightLength / height)) / 2
- startPoint = { ...startPoint, x1: halfWidthLength - halfModuleWidthLength, y1: startPoint.y1 - heightMargin }
- }
+ if (moduleIndex === 0) {
+ flowLines = getFlowLines(moduleSetupSurface, height)
+ if (flowLines.top.type === 'curve') {
+ flowLines = getFlowLines(moduleSetupSurface, width)
}
}
- // else {
- // //중앙배치가 아닐때도 흐름 방향 기준면으로 양면이 직선이면 가운데 배치
- // if (flowModuleLine.bottom.type === 'flat' && flowModuleLine.left.type === 'flat' && flowModuleLine.right.type === 'flat') {
- // //하단 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치
- // const halfWidthLength = Math.abs(startPoint.x1 + startPoint.x2) / 2 //밑에 길이에서 반을 가른다
- // const halfModuleWidthLength = width / 2
- // startPoint = { ...startPoint, x1: halfWidthLength - halfModuleWidthLength }
- // }
- // }
- const maxLeftEndPoint = surfaceMaxLines.left.x1 //최 좌측
- const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측
- const maxBottomEndPoint = surfaceMaxLines.bottom.y1 //최하단
+ //흐름 방향이 북쪽(위)
- let totalLeftEndPoint = maxLeftEndPoint - startPoint.x1
- let totalRightEndPoint = maxLeftEndPoint - maxRightEndPoint
- let totalBottomEndPoint = maxBottomEndPoint - startPoint.y1
- let diffLeftEndPoint = Math.abs(totalLeftEndPoint / width)
- let diffRightEndPoint = Math.ceil(Math.abs(totalRightEndPoint / width))
- let diffBottomEndPoint = Math.ceil(Math.abs(totalBottomEndPoint / height))
- let startColPoint = Math.abs(width * Math.ceil(diffLeftEndPoint) - startPoint.x1)
- let tempMaxWidth = isMaxSetup ? width / 2 : width //최대배치인지 확인하려고 넣음
- if (isMaxSetup) diffRightEndPoint = diffRightEndPoint * 2 //최대배치시 2배로 늘려서 반씩 검사하기위함
+ //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음
+ const moduleArray = []
- startColPoint = Math.round(startColPoint - intvHor * diffRightEndPoint)
+ let calcAreaWidth = flowLines.right.x1 - flowLines.left.x1 //오른쪽 x에서 왼쪽 x를 뺀 가운데를 찾는 로직
+ let calcModuleWidthCount = calcAreaWidth / (width + intvHor + 1) //뺀 공간에서 모듈을 몇개를 넣을수 있는지 확인하는 로직
+ let calcMaxModuleWidthCount = calcModuleWidthCount > moduleMaxCols ? moduleMaxCols : calcModuleWidthCount //최대 모듈 단수가 있기 때문에 최대 단수보다 카운트가 크면 최대 단수로 씀씀
+ // let totalModuleWidthCount = isChidori ? Math.abs(calcMaxModuleWidthCount) : Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다 //??어쩔때는 붙고 어쩔때는 안붙고 멋대로???
+ let totalModuleWidthCount = Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다
- for (let j = 0; j < diffBottomEndPoint; j++) {
- bottomMargin = j === 0 ? 0 : intvVer * j
- for (let i = 0; i < diffRightEndPoint; i++) {
- leftMargin = i === 0 ? 0 : intvHor * i
+ let calcAreaHeight = flowLines.bottom.y1 - flowLines.top.y1
+ let calcModuleHeightCount = calcAreaHeight / (height + intvVer + 1)
+
+ let calcStartPoint = flowLines.left.type === 'flat' ? (calcAreaWidth - totalModuleWidthCount * width) / 2 : 0 //반씩 나눠서 중앙에 맞춤 bottom 기준으로 양변이 직선일때만 가운데 정렬
+ let startPointX = flowLines.right.x1 - calcStartPoint //시작점을 만든다
+
+ //근데 양변이 곡선이면 중앙에 맞추기 위해 아래와 위의 길이를 재서 모듈의 길이를 나눠서 들어갈수 있는 갯수가 동일하면 가운데로 정렬 시킨다
+ if (flowLines.left.type === 'curve' && flowLines.right.type === 'curve') {
+ startPointX = flowLines.right.x1 - (calcAreaWidth - totalModuleWidthCount * width) / 2
+ }
+
+ let heightMargin = 0
+ let widthMargin = 0
+ let chidoriLength = 0
+
+ if (moduleIndex > 0) {
+ moduleMaxRows = totalModuleMaxRows - installedModuleHeightCount //두번째 모듈일때
+ isChidoriLine = installedModuleHeightCount % 2 != 0 ? true : false //첫번째에서 짝수에서 끝났으면 홀수는 치도리가 아님 짝수는 치도리
+ }
+
+ for (let i = 0; i < calcModuleHeightCount; i++) {
+ let isInstall = false
+ let moduleY = flowLines.top.y1 + height * i //탑의 y점에서부터 아래로 그려 내려간다
+
+ if (moduleIndex > 0) {
+ moduleY = installedLastHeightCoord + intvVer + 1
+ }
+
+ heightMargin = i === 0 ? 0 : intvVer * i //모듈간에 마진이 있어 마진값도 넣음
+ for (let j = 0; j < totalModuleWidthCount; j++) {
+ //모듈 열수 만큼 반복
+ let moduleX = startPointX - width * j - 1 //시작점에서 우 -> 좌로 그려 내려간다
+ widthMargin = j === 0 ? 0 : intvHor * j
chidoriLength = 0
if (isChidori && !isMaxSetup) {
- chidoriLength = j % 2 === 0 ? 0 : width / 2 - intvHor
+ chidoriLength = installedModuleHeightCount % 2 == 0 ? 0 : width / 2 - intvHor
}
- square = [
- [startColPoint + tempMaxWidth * i + chidoriLength + leftMargin, startPoint.y1 + height * j + bottomMargin],
- [startColPoint + tempMaxWidth * i + chidoriLength + leftMargin, startPoint.y1 + height * j + height + bottomMargin],
- [startColPoint + tempMaxWidth * i + width + chidoriLength + leftMargin, startPoint.y1 + height * j + height + bottomMargin],
- [startColPoint + tempMaxWidth * i + width + chidoriLength + leftMargin, startPoint.y1 + height * j + bottomMargin],
- [startColPoint + tempMaxWidth * i + chidoriLength + leftMargin, startPoint.y1 + height * j + bottomMargin],
+ if (isChidori && isChidoriLine) {
+ chidoriLength = width / 2 + intvHor
+ }
+
+ let square = [
+ [moduleX - widthMargin - chidoriLength, moduleY + heightMargin],
+ [moduleX - widthMargin - chidoriLength, moduleY + height + heightMargin],
+ [moduleX - width - widthMargin - chidoriLength, moduleY + height + heightMargin],
+ [moduleX - width - widthMargin - chidoriLength, moduleY + heightMargin],
+ [moduleX - widthMargin - chidoriLength, moduleY + heightMargin],
]
let squarePolygon = turf.polygon([square])
let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1)
let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] }))
- // if (disjointFromTrestle && isDisjoint) {
moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id, moduleInfo: module }
let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon })
@@ -1168,31 +1178,165 @@ export function useModuleBasicSetting(tabNum) {
let isDisjoint = checkModuleDisjointObjects(squarePolygon, containsBatchObjects)
if (disjointFromTrestle && isDisjoint) {
- if (index > 0) {
- setupModule.forEach((item) => {
- const isOverlap = item.some((item2) => turf.booleanOverlap(squarePolygon, polygonToTurfPolygon(item2, true)))
- if (!isOverlap) {
- canvas?.add(tempModule)
- moduleSetupArray.push(tempModule)
- moduleArray.push(tempModule)
- canvas.renderAll()
- }
- })
- } else {
- //최초 한번은 그냥 그린다
- //겹치는지 확인해서 포함된 모듈만 그린다
- canvas?.add(tempModule)
- moduleSetupArray.push(tempModule)
- moduleArray.push(tempModule)
- canvas.renderAll()
- }
+ canvas?.add(tempModule)
+ moduleSetupArray.push(tempModule)
+ moduleArray.push(tempModule)
+ canvas.renderAll()
+
+ isInstall = true
+
+ //마지막에 설치된 모듈의 Y 좌표
+ installedLastHeightCoord = moduleY + height + heightMargin
} else {
//디버깅용
- // tempModule.set({ fill: 'rgba(255,190,41, 0.4)', stroke: 'black', strokeWidth: 1 })
+ // tempModule.set({ fill: 'transparent', stroke: 'red', strokeWidth: 1 })
// canvas?.add(tempModule)
// canvas.renderAll()
}
}
+ if (isInstall) {
+ ++installedModuleHeightCount
+ }
+ }
+
+ setupModule.push(moduleArray)
+ })
+ }
+
+ //남, 북과 같은 로직으로 적용하려면 좌우는 열 -> 행 으로 그려야함
+ //변수명은 bottom 기준으로 작성하여 동일한 방향으로 진행한다
+ const leftFlowSetupModule = (
+ surfaceMaxLines,
+ maxLengthLine,
+ moduleSetupArray,
+ moduleSetupSurface,
+ containsBatchObjects,
+ isCenter = false,
+ intvHor,
+ intvVer,
+ ) => {
+ let setupModule = []
+
+ const trestleDetailData = moduleSetupSurface.trestleDetail //가대 상세 데이터
+ const moduleMaxCols = trestleDetailData.moduleMaxCols // 모듈 최대 가로 설치 갯수
+
+ let installedLastHeightCoord = 0 //마지막으로 설치된 모듈의 좌표
+ let installedModuleHeightCount = 0 //마지막으로 설치된 모듈의 카운트
+ let isChidoriLine = false
+ let flowLines
+
+ checkedModule.forEach((module, moduleIndex) => {
+ const tmpModuleData = trestleDetailData.module.filter((moduleObj) => module.moduleTpCd === moduleObj.moduleTpCd)[0]
+ //혼합모듈일때는 mixModuleMaxRows 값이 0 이상임
+ let moduleMaxRows = tmpModuleData.mixModuleMaxRows === 0 ? tmpModuleData.moduleMaxRows : tmpModuleData.mixModuleMaxRows
+
+ // 혼합모듈 포함 총 모듈 설치 높이 갯수
+ const totalModuleMaxRows = tmpModuleData.moduleMaxRows
+
+ //모듈의 넓이 높이를 가져옴 (복시도 촌수 적용)
+ //1번 깔았던 모듈 기준으로 잡야아함
+ const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
+
+ if (moduleIndex === 0) {
+ flowLines = getFlowLines(moduleSetupSurface, width)
+ if (flowLines.left.type === 'curve') {
+ flowLines = getFlowLines(moduleSetupSurface, height)
+ }
+ }
+
+ //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음
+
+ const moduleArray = []
+
+ let calcAreaWidth = flowLines.bottom.y1 - flowLines.top.y1 //아래에서 y에서 위를 y를 뺀 가운데를 찾는 로직
+ let calcModuleWidthCount = calcAreaWidth / (height + intvHor + 1) //뺀 공간에서 모듈을 몇개를 넣을수 있는지 확인하는 로직
+ let calcMaxModuleWidthCount = calcModuleWidthCount > moduleMaxCols ? moduleMaxCols : calcModuleWidthCount //최대 모듈 단수가 있기 때문에 최대 단수보다 카운트가 크면 최대 단수로 씀씀
+ // let totalModuleWidthCount = isChidori ? Math.abs(calcMaxModuleWidthCount) : Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다
+ let totalModuleWidthCount = Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다
+
+ let calcAreaHeight = flowLines.right.x1 - flowLines.left.x1
+ let calcModuleHeightCount = calcAreaHeight / (width + intvVer + 1)
+
+ let calcStartPoint = flowLines.bottom.type === 'flat' ? (calcAreaWidth - totalModuleWidthCount * height) / 2 : 0 //반씩 나눠서 중앙에 맞춤 left 높이 기준으로 양변이 직선일때만 가운데 정렬
+ let startPointX = flowLines.top.y1 + calcStartPoint //시작점을 만든다
+
+ //근데 양변이 곡선이면 중앙에 맞추기 위해 아래와 위의 길이를 재서 모듈의 길이를 나눠서 들어갈수 있는 갯수가 동일하면 가운데로 정렬 시킨다
+ if (flowLines.top.type === 'curve' && flowLines.bottom.type === 'curve') {
+ startPointX = flowLines.top.y1 + (calcAreaWidth - totalModuleWidthCount * height) / 2
+ }
+
+ let heightMargin = 0
+ let widthMargin = 0
+ let chidoriLength = 0
+
+ //첫번재 모듈 설치 후 두번째 모듈을 몇개까지 설치 할 수 있는지 계산
+ if (moduleIndex > 0) {
+ moduleMaxRows = totalModuleMaxRows - installedModuleHeightCount //두번째 모듈일때
+ isChidoriLine = installedModuleHeightCount % 2 != 0 ? true : false //첫번째에서 짝수에서 끝났으면 홀수는 치도리가 아님 짝수는 치도리
+ }
+
+ for (let i = 0; i < calcModuleHeightCount; i++) {
+ let isInstall = false
+ let moduleY = flowLines.left.x1 + width * i + 1 //살짝 여유를 준다
+
+ //두번째 모듈 -> 혼합일 경우의 설치될 모듈 높이를 계산
+ if (moduleIndex > 0) {
+ moduleY = installedLastHeightCoord + intvHor
+ }
+
+ //첫번째는 붙여서 두번째는 마진을 주고 설치
+ heightMargin = i === 0 ? 0 : intvHor * i
+
+ for (let j = 0; j < totalModuleWidthCount; j++) {
+ let moduleX = startPointX + height * j + 1 //5정도 마진을 준다
+ widthMargin = j === 0 ? 0 : intvVer * j // 가로 마진값
+ chidoriLength = 0 //치도리가 아니여도 기본값을 5정도 준다
+ if (isChidori && !isMaxSetup) {
+ chidoriLength = installedModuleHeightCount % 2 == 0 ? 0 : height / 2 - intvVer
+ }
+
+ let square = [
+ [moduleY + heightMargin, moduleX + height + widthMargin + chidoriLength],
+ [moduleY + heightMargin, moduleX + widthMargin + chidoriLength],
+ [moduleY + width + heightMargin, moduleX + widthMargin + chidoriLength],
+ [moduleY + width + heightMargin, moduleX + height + widthMargin + chidoriLength],
+ [moduleY + heightMargin, moduleX + height + widthMargin + chidoriLength],
+ ]
+
+ let squarePolygon = turf.polygon([square])
+ let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1)
+ let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] }))
+
+ moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id, moduleInfo: module }
+ let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon })
+
+ let disjointFromTrestle = checkModuleDisjointSurface(squarePolygon, polygonToTurfPolygon(moduleSetupSurface, true))
+ let isDisjoint = checkModuleDisjointObjects(squarePolygon, containsBatchObjects)
+
+ if (disjointFromTrestle && isDisjoint) {
+ //최초 한번은 그냥 그린다
+ //겹치는지 확인해서 포함된 모듈만 그린다
+ canvas?.add(tempModule)
+ moduleSetupArray.push(tempModule)
+ moduleArray.push(tempModule)
+ canvas.renderAll()
+
+ // ++installedModuleHeightCount
+
+ isInstall = true
+ //마지막에 설치된 모듈의 Y 좌표
+ installedLastHeightCoord = moduleY + width + widthMargin
+ } else {
+ //디버깅용
+ // tempModule.set({ fill: 'transparent', stroke: 'red', strokeWidth: 1 })
+ // canvas?.add(tempModule)
+ // canvas.renderAll()
+ }
+ }
+
+ if (isInstall) {
+ ++installedModuleHeightCount
+ }
}
setupModule.push(moduleArray)
})
@@ -1210,108 +1354,130 @@ export function useModuleBasicSetting(tabNum) {
) => {
let setupModule = []
- checkedModule.forEach((module, index) => {
+ const trestleDetailData = moduleSetupSurface.trestleDetail //가대 상세 데이터
+ const moduleMaxCols = trestleDetailData.moduleMaxCols // 모듈 최대 가로 설치 갯수
+
+ let installedLastHeightCoord = 0 //마지막으로 설치된 모듈의 좌표
+ let installedModuleHeightCount = 0 //마지막으로 설치된 모듈의 카운트
+ let isChidoriLine = false
+ let flowLines
+
+ checkedModule.forEach((module, moduleIndex) => {
+ const tmpModuleData = trestleDetailData.module.filter((moduleObj) => module.moduleTpCd === moduleObj.moduleTpCd)[0]
+ //혼합모듈일때는 mixModuleMaxRows 값이 0 이상임
+ let moduleMaxRows = tmpModuleData.mixModuleMaxRows === 0 ? tmpModuleData.moduleMaxRows : tmpModuleData.mixModuleMaxRows
+
+ // 혼합모듈 포함 총 모듈 설치 높이 갯수
+ const totalModuleMaxRows = tmpModuleData.moduleMaxRows
+
+ //모듈의 넓이 높이를 가져옴 (복시도 촌수 적용)
+ //1번 깔았던 모듈 기준으로 잡야아함
const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
- let flowLines = getFlowLines(moduleSetupSurface, width)
- let startPoint = flowLines.right
- // if (flowLines.right.type === 'flat') {
- // const tempPoint = { ...flowLines.bottom }
- // startPoint = { ...flowLines.bottom, x1: tempPoint.x2, x2: tempPoint.x1 }
- // } else {
- // flowLines = getFlowLines(moduleSetupSurface, height)
- // const tempPoint = { ...flowLines.right }
- // startPoint = { ...flowLines.right, x1: tempPoint.x1 - 5, x2: tempPoint.x2, y1: tempPoint.y1 + 5 }
- // }
-
- // console.log('startPoint', startPoint)
-
- const moduleArray = []
-
- if (isCenter) {
- if (flowLines.left.type === 'flat' && flowLines.bottom.type === 'flat' && flowLines.top.type === 'flat') {
- //좌측 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치
- const halfWidthLength = Math.abs(startPoint.y1 + startPoint.y2) / 2 //밑에 길이에서 반을 가른다
- const halfModuleWidthLength = height / 2
- startPoint = { ...startPoint, y1: halfWidthLength + halfModuleWidthLength }
-
- if (flowLines.right.type === 'flat') {
- //우측까지 평면이면 직사각,정사각이라 가정하고 상자의 중심으로 계산
- const widthLength = Math.abs(flowLines.top.x1 - flowLines.top.x2) //옆에에 길이에서 반을 가른다
- const widthMargin = Math.abs(widthLength - width * Math.floor(widthLength / width)) / 2
- startPoint = { ...startPoint, x1: startPoint.x1 - widthMargin }
- }
+ if (moduleIndex === 0) {
+ flowLines = getFlowLines(moduleSetupSurface, width)
+ if (flowLines.right.type === 'curve') {
+ flowLines = getFlowLines(moduleSetupSurface, height)
}
}
- const maxLeftEndPoint = surfaceMaxLines.left.x1 //최 좌측
- const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단
- const maxBottomEndPoint = surfaceMaxLines.bottom.y1 //최하단
+ //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음
+ const moduleArray = []
- let totalTopEndPoint = Math.abs(maxTopEndPoint - startPoint.y1) //전체 높이에서 현재 높이를 뺌
- let diffTopEndPoint = Math.abs(totalTopEndPoint / height)
- let totalHeight = Math.ceil(Math.abs(maxBottomEndPoint - maxTopEndPoint) / height)
- let totalWidth = Math.abs(startPoint.x1 - maxLeftEndPoint) / width
- let startRowPoint = startPoint.y1 - height * Math.ceil(diffTopEndPoint) - 4 // -3으로 위치살짝 보정1
+ let calcAreaWidth = flowLines.bottom.y1 - flowLines.top.y1 //아래에서 y에서 위를 y를 뺀 가운데를 찾는 로직
+ let calcModuleWidthCount = calcAreaWidth / (height + intvHor + 1) //뺀 공간에서 모듈을 몇개를 넣을수 있는지 확인하는 로직
+ let calcMaxModuleWidthCount = calcModuleWidthCount > moduleMaxCols ? moduleMaxCols : calcModuleWidthCount //최대 모듈 단수가 있기 때문에 최대 단수보다 카운트가 크면 최대 단수로 씀씀
+ // let totalModuleWidthCount = isChidori ? Math.abs(calcMaxModuleWidthCount) : Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다
+ let totalModuleWidthCount = Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다
- let tempMaxHeight = isMaxSetup ? height / 2 : height //최대배치인지 확인하려고 넣음
- if (isMaxSetup) totalHeight = totalHeight * 2 //최대배치시 2배로 늘려서 반씩 검사
+ let calcAreaHeight = flowLines.right.x1 - flowLines.left.x1
+ let calcModuleHeightCount = calcAreaHeight / (width + intvVer + 1)
- for (let i = 0; i <= totalWidth; i++) {
- bottomMargin = i === 0 ? 0 : -(intvHor * i)
- for (let j = 0; j < totalHeight; j++) {
- leftMargin = j === 0 ? 0 : intvVer * j
+ let calcStartPoint = flowLines.top.type === 'flat' ? (calcAreaWidth - totalModuleWidthCount * height) / 2 : 0 //반씩 나눠서 중앙에 맞춤 left 높이 기준으로 양변이 직선일때만 가운데 정렬
+ let startPointX = flowLines.bottom.y2 - calcStartPoint //시작점을 만든다
- chidoriLength = 0
+ //근데 양변이 곡선이면 중앙에 맞추기 위해 아래와 위의 길이를 재서 모듈의 길이를 나눠서 들어갈수 있는 갯수가 동일하면 가운데로 정렬 시킨다
+ if (flowLines.top.type === 'curve' && flowLines.bottom.type === 'curve') {
+ startPointX = flowLines.bottom.y2 - (calcAreaWidth - totalModuleWidthCount * height) / 2
+ }
+
+ let heightMargin = 0
+ let widthMargin = 0
+ let chidoriLength = 0
+
+ //첫번재 모듈 설치 후 두번째 모듈을 몇개까지 설치 할 수 있는지 계산
+ if (moduleIndex > 0) {
+ moduleMaxRows = totalModuleMaxRows - installedModuleHeightCount //두번째 모듈일때
+ isChidoriLine = installedModuleHeightCount % 2 != 0 ? true : false //첫번째에서 짝수에서 끝났으면 홀수는 치도리가 아님 짝수는 치도리
+ }
+
+ for (let i = 0; i < calcModuleHeightCount; i++) {
+ let isInstall = false
+ let moduleY = flowLines.right.x1 - width * i - 1 //살짝 여유를 준다
+
+ //두번째 모듈 -> 혼합일 경우의 설치될 모듈 높이를 계산
+ if (moduleIndex > 0) {
+ moduleY = installedLastHeightCoord - intvHor
+ }
+
+ //첫번째는 붙여서 두번째는 마진을 주고 설치
+ heightMargin = i === 0 ? 0 : intvHor * i
+
+ for (let j = 0; j < totalModuleWidthCount; j++) {
+ let moduleX = startPointX - height * j - 1 //5정도 마진을 준다
+ widthMargin = j === 0 ? 0 : intvVer * j // 가로 마진값
+ chidoriLength = 0 //치도리가 아니여도 기본값을 5정도 준다
if (isChidori && !isMaxSetup) {
- chidoriLength = i % 2 === 0 ? 0 : height / 2 - intvHor
+ chidoriLength = installedModuleHeightCount % 2 == 0 ? 0 : height / 2 - intvVer
}
- square = [
- [startPoint.x1 - width * i + bottomMargin, startRowPoint - intvHor + tempMaxHeight * j + leftMargin + chidoriLength],
- [startPoint.x1 - width * i - width + bottomMargin, startRowPoint - intvHor + tempMaxHeight * j + leftMargin + chidoriLength],
- [startPoint.x1 - width * i - width + bottomMargin, startRowPoint - intvHor + tempMaxHeight * j + height + leftMargin + chidoriLength],
- [startPoint.x1 - width * i + bottomMargin, startRowPoint - intvHor + tempMaxHeight * j + height + leftMargin + chidoriLength],
- [startPoint.x1 - width * i + bottomMargin, startRowPoint - intvHor + tempMaxHeight * j + leftMargin + chidoriLength],
+ //치도리 일때 는 짝수(1 기준) 일때만 치도리 라인으로 본다
+ // if (isChidori && isChidoriLine) {
+ // chidoriLength = width / 2 - height
+ // }
+
+ let square = [
+ [moduleY - heightMargin, moduleX - height - widthMargin - chidoriLength],
+ [moduleY - heightMargin, moduleX - widthMargin - chidoriLength],
+ [moduleY - width - heightMargin, moduleX - widthMargin - chidoriLength],
+ [moduleY - width - heightMargin, moduleX - height - widthMargin - chidoriLength],
+ [moduleY - heightMargin, moduleX - height - widthMargin - chidoriLength],
]
let squarePolygon = turf.polygon([square])
let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1)
let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] }))
- // if (disjointFromTrestle && isDisjoint) {
moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id, moduleInfo: module }
let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon })
+
let disjointFromTrestle = checkModuleDisjointSurface(squarePolygon, polygonToTurfPolygon(moduleSetupSurface, true))
let isDisjoint = checkModuleDisjointObjects(squarePolygon, containsBatchObjects)
if (disjointFromTrestle && isDisjoint) {
- if (index > 0) {
- setupModule.forEach((item) => {
- const isOverlap = item.some((item2) => turf.booleanOverlap(squarePolygon, polygonToTurfPolygon(item2, true)))
- if (!isOverlap) {
- canvas?.add(tempModule)
- moduleSetupArray.push(tempModule)
- moduleArray.push(tempModule)
- canvas.renderAll()
- }
- })
- } else {
- //최초 한번은 그냥 그린다
- //겹치는지 확인해서 포함된 모듈만 그린다
- canvas?.add(tempModule)
- moduleSetupArray.push(tempModule)
- moduleArray.push(tempModule)
- canvas.renderAll()
- }
+ //최초 한번은 그냥 그린다
+ //겹치는지 확인해서 포함된 모듈만 그린다
+ canvas?.add(tempModule)
+ moduleSetupArray.push(tempModule)
+ moduleArray.push(tempModule)
+ canvas.renderAll()
+
+ isInstall = true
+ //마지막에 설치된 모듈의 Y 좌표
+ installedLastHeightCoord = moduleY - width - heightMargin
} else {
//디버깅용
- // tempModule.set({ fill: 'rgba(255,190,41, 0.4)', stroke: 'black', strokeWidth: 1 })
+ // tempModule.set({ fill: 'transparent', stroke: 'red', strokeWidth: 1 })
// canvas?.add(tempModule)
// canvas.renderAll()
}
}
+
+ if (isInstall) {
+ ++installedModuleHeightCount
+ }
}
+
setupModule.push(moduleArray)
})
}
@@ -1416,7 +1582,8 @@ export function useModuleBasicSetting(tabNum) {
})
moduleSetupSurface.set({ modules: moduleSetupArray })
- getModuleStatistics()
+ // getModuleStatistics()
+ setModuleStatisticsData()
// const moduleArray = [...moduleIsSetup]
// moduleArray.push({
// surfaceId: moduleSetupSurface.surfaceId,
@@ -1516,6 +1683,7 @@ export function useModuleBasicSetting(tabNum) {
const pointX2 = coords[2].x + ((coords[2].y - top) / (coords[2].y - coords[1].y)) * (coords[1].x - coords[2].x)
const pointY2 = top
+ //디버깅
const finalLine = new QLine([pointX1, pointY1, pointX2, pointY2], {
stroke: 'red',
strokeWidth: 1,
@@ -1524,8 +1692,8 @@ export function useModuleBasicSetting(tabNum) {
// console.log(`index ${index} : finalLine`, pointX1, pointY1, pointX2, pointY2)
- canvas?.add(finalLine)
- canvas?.renderAll()
+ // canvas?.add(finalLine)
+ // canvas?.renderAll()
let rtnObj
//평평하면
@@ -1562,7 +1730,6 @@ export function useModuleBasicSetting(tabNum) {
rtnObjArray.push(rtnObj)
})
-
return rtnObjArray
}
@@ -1642,13 +1809,14 @@ export function useModuleBasicSetting(tabNum) {
const pointX2 = top
const pointY2 = coords[2].y + ((coords[2].x - top) / (coords[2].x - coords[1].x)) * (coords[1].y - coords[2].y)
+ //디버깅용
const finalLine = new QLine([pointX1, pointY1, pointX2, pointY2], {
stroke: 'red',
strokeWidth: 1,
selectable: true,
})
- canvas?.add(finalLine)
- canvas?.renderAll()
+ // canvas?.add(finalLine)
+ // canvas?.renderAll()
let rtnObj
//평평하면
@@ -1768,7 +1936,7 @@ export function useModuleBasicSetting(tabNum) {
let moduleOptions = {
fill: '#BFFD9F',
stroke: 'black',
- strokeWidth: 0.1,
+ strokeWidth: 0.3,
selectable: true, // 선택 가능하게 설정
lockMovementX: true, // X 축 이동 잠금
lockMovementY: true, // Y 축 이동 잠금
@@ -1836,7 +2004,7 @@ export function useModuleBasicSetting(tabNum) {
let tmpHeight = flowDirection === 'south' || flowDirection === 'north' ? moduleHeight : moduleWidth
let { width, height } =
- canvasSetting.roofSizeSet === '1'
+ canvasSetting.roofSizeSet == '1'
? calculateVisibleModuleHeight(tmpWidth, tmpHeight, getDegreeByChon(moduleSetupSurfaces[i].roofMaterial.pitch), flowDirection)
: { width: tmpWidth, height: tmpHeight }
@@ -1879,7 +2047,7 @@ export function useModuleBasicSetting(tabNum) {
* 스냅기능
*/
let snapDistance = 10
- let cellSnapDistance = 20
+ let cellSnapDistance = 50
let intvHor = flowDirection === 'south' || flowDirection === 'north' ? 1 : 3
let intvVer = flowDirection === 'south' || flowDirection === 'north' ? 3 : 1
@@ -2064,12 +2232,13 @@ export function useModuleBasicSetting(tabNum) {
if (turf.booleanWithin(tempTurfModule, turfPolygon)) {
//마우스 클릭시 set으로 해당 위치에 셀을 넣음
- const isOverlap = manualDrawModules.some((module) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(module))) //겹치는지 확인
+ const isOverlap = manualDrawModules.some((module) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(module, true))) //겹치는지 확인
if (!isOverlap) {
moduleOptions.surfaceId = trestlePolygon.id
let manualModule = new QPolygon(tempModule.points, { ...moduleOptions, moduleInfo: checkedModule[0] })
canvas?.add(manualModule)
- manualDrawModules.push(tempModule)
+ manualDrawModules.push(manualModule)
+ setModuleStatisticsData()
} else {
swalFire({ text: getMessage('module.place.overlab') })
}
@@ -2079,7 +2248,8 @@ export function useModuleBasicSetting(tabNum) {
}
})
}
- getModuleStatistics()
+ // getModuleStatistics()
+ setModuleStatisticsData()
} else {
if (moduleSetupSurfaces) {
//수동모드 해제시 모듈 설치면 선택 잠금
@@ -2157,8 +2327,13 @@ export function useModuleBasicSetting(tabNum) {
targetRoof.angle = -angle
targetSurface.angle = -angle
+ const newLines = createLinesFromPolygon(targetSurface.getCurrentPoints())
+ targetSurface.set({ lines: newLines })
+
targetRoof.fire('modified')
targetSurface.fire('modified')
+ targetRoof.setCoords()
+ targetSurface.setCoords()
moduleSetupSurfaces.push(targetSurface)
}
canvas.remove(obj)
@@ -2203,7 +2378,7 @@ export function useModuleBasicSetting(tabNum) {
let moduleOptions = {
fill: '#BFFD9F',
stroke: 'black',
- strokeWidth: 0.1,
+ strokeWidth: 0.3,
selectable: true, // 선택 가능하게 설정
lockMovementX: true, // X 축 이동 잠금
lockMovementY: true, // Y 축 이동 잠금
@@ -2252,37 +2427,92 @@ export function useModuleBasicSetting(tabNum) {
let moduleGroup = []
- const flatRoofDownFlowSetupModule = (surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) => {
- checkedModule.forEach((module, index) => {
- const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
+ const flatRoofDownFlowSetupModule = (
+ surfaceMaxLines,
+ maxLengthLine,
+ moduleSetupArray,
+ moduleSetupSurface,
+ intvHor,
+ intvVer,
+ containsBatchObjects,
+ ) => {
+ let setupModule = []
- const flowLines = getFlowLines(moduleSetupSurface, height)
+ let installedLastHeightCoord = 0 //마지막으로 설치된 모듈의 좌표
+ let installedModuleHeightCount = 0 //마지막으로 설치된 모듈의 카운트
+ let flowLines
- let startPoint = flowLines.bottom
+ checkedModule.forEach((module, moduleIndex) => {
+ //모듈의 넓이 높이를 가져옴 (복시도 촌수 적용)
+ //1번 깔았던 모듈 기준으로 잡야아함
+ let { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
- const maxLeftEndPoint = surfaceMaxLines.left.x1 //최 좌측
- const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측
- const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단
+ if (moduleIndex === 0) {
+ flowLines = getFlowLines(moduleSetupSurface, height)
+ if (flowLines.bottom.type === 'curve') {
+ flowLines = getFlowLines(moduleSetupSurface, width)
+ }
+ }
- let totalLeftEndPoint = maxLeftEndPoint - startPoint.x1
- let totalTopEndPoint = maxTopEndPoint - startPoint.y1
- let totalWidth = Math.ceil(Math.abs(maxRightEndPoint - maxLeftEndPoint) / width)
- let diffLeftEndPoint = Math.abs(totalLeftEndPoint / width)
- let diffTopEndPoint = Math.abs(totalTopEndPoint / height)
- let startColPoint = Math.abs(width * Math.ceil(diffLeftEndPoint) - startPoint.x1)
- let tempMaxWidth = width //최대배치인지 확인하려고 넣음
+ //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음
+ const moduleArray = []
- for (let j = 0; j < diffTopEndPoint; j++) {
- bottomMargin = marginHeight * j
- for (let i = 0; i <= totalWidth; i++) {
- leftMargin = marginWidth * i
+ let calcAreaWidth = flowLines.right.x1 - flowLines.left.x1 //오른쪽 x에서 왼쪽 x를 뺀 가운데를 찾는 로직
+ let calcModuleWidthCount = calcAreaWidth / (width + intvHor) //뺀 공간에서 모듈을 몇개를 넣을수 있는지 확인하는 로직
+ let calcMaxModuleWidthCount = calcModuleWidthCount //최대 모듈 단수가 있기 때문에 최대 단수보다 카운트가 크면 최대 단수로 씀씀
+ let totalModuleWidthCount = Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다
- square = [
- [startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 - height * j - bottomMargin],
- [startColPoint + tempMaxWidth * i + width + leftMargin, startPoint.y1 - height * j - bottomMargin],
- [startColPoint + tempMaxWidth * i + width + leftMargin, startPoint.y1 - height * j - height - bottomMargin],
- [startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 - height * j - height - bottomMargin],
- [startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 - height * j - bottomMargin],
+ let calcAreaheight = flowLines.bottom.y1 - flowLines.top.y1 //오른쪽 y에서 왼쪽 y를 뺀 가운데를 찾는 로직
+ let calcModuleHeightCount = calcAreaheight / (height + intvVer) //뺀 공간에서 모듈을 몇개를 넣을수 있는지 확인하는 로직
+ let calcMaxModuleHeightCount = calcModuleHeightCount //최대 모듈 단수가 있기 때문에 최대 단수보다 카운트가 크면 최대 단수로 씀씀
+ let totalModuleHeightCount = Math.floor(calcMaxModuleHeightCount) //치조배치일경우는 한개 더 넣는다
+
+ let calcStartPoint = flowLines.right.type === 'flat' ? (calcAreaWidth - totalModuleWidthCount * width) / 2 : 0 //반씩 나눠서 중앙에 맞춤 bottom 기준으로 양변이 직선일때만 가운데 정렬
+ let startPointX = flowLines.left.x1 + calcStartPoint //시작점을 만든다
+
+ //근데 양변이 곡선이면 중앙에 맞추기 위해 아래와 위의 길이를 재서 모듈의 길이를 나눠서 들어갈수 있는 갯수가 동일하면 가운데로 정렬 시킨다
+ if (flowLines.left.type === 'curve' && flowLines.right.type === 'curve') {
+ startPointX = flowLines.left.x1 + (calcAreaWidth - totalModuleWidthCount * width) / 2
+
+ if (flowLines.left.x1 < flowLines.bottom.x1) {
+ startPointX = flowLines.left.x1
+ }
+ }
+
+ let heightMargin = 0
+ let widthMargin = 0
+ let chidoriLength = 0
+ let moduleMaxRows = totalModuleHeightCount
+
+ //첫번재 모듈 설치 후 두번째 모듈을 몇개까지 설치 할 수 있는지 계산
+ if (moduleIndex > 0) {
+ moduleMaxRows = moduleMaxRows - installedModuleHeightCount //두번째 모듈일때
+ }
+
+ let isInstall = false
+
+ for (let i = 0; i < moduleMaxRows; i++) {
+ let moduleY = flowLines.bottom.y1 - height * i - 1 //살짝 여유를 준다
+
+ //두번째 모듈 -> 혼합일 경우의 설치될 모듈 높이를 계산
+ if (moduleIndex > 0) {
+ moduleY = installedLastHeightCoord - intvVer
+ }
+
+ //첫번째는 붙여서 두번째는 마진을 주고 설치
+ heightMargin = i === 0 ? 0 : intvVer * i
+
+ for (let j = 0; j < totalModuleWidthCount; j++) {
+ let moduleX = startPointX + width * j + 1 //5정도 마진을 준다
+ widthMargin = j === 0 ? 0 : intvHor * j // 가로 마진값
+ chidoriLength = 0 //치도리가 아니여도 기본값을 5정도 준다
+
+ let square = [
+ [moduleX + widthMargin, moduleY - height - heightMargin],
+ [moduleX + widthMargin, moduleY - heightMargin],
+ [moduleX + width + widthMargin, moduleY - heightMargin],
+ [moduleX + width + widthMargin, moduleY - height - heightMargin],
+ [moduleX + widthMargin, moduleY - height - heightMargin],
]
let squarePolygon = turf.polygon([square])
@@ -2291,148 +2521,35 @@ export function useModuleBasicSetting(tabNum) {
moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id, moduleInfo: module }
let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon })
- canvas?.add(tempModule)
- moduleSetupArray.push(tempModule)
- moduleGroup.push(tempModule)
- }
- }
- })
- }
-
- const flatRoofLeftFlowSetupModule = (surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) => {
- checkedModule.forEach((module, index) => {
- const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
- const flowLines = getFlowLines(moduleSetupSurface, width)
- let startPoint = flowLines.left
-
- const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측
- const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단
- const maxBottomEndPoint = surfaceMaxLines.bottom.y1 //최하단
-
- let totalTopEndPoint = Math.abs(maxTopEndPoint - startPoint.y1) //전체 높이에서 현재 높이를 뺌
- let diffTopEndPoint = Math.abs(totalTopEndPoint / height)
- let totalHeight = Math.ceil(Math.abs(maxBottomEndPoint - maxTopEndPoint) / height)
- let totalWidth = Math.abs(startPoint.x1 - maxRightEndPoint) / width
- let startRowPoint = startPoint.y1 - height * Math.ceil(diffTopEndPoint)
- let tempMaxHeight = height //최대배치인지 확인하려고 넣음
-
- for (let i = 0; i <= totalWidth; i++) {
- bottomMargin = marginHeight * i
- for (let j = 0; j < totalHeight; j++) {
- leftMargin = marginWidth * j
-
- square = [
- [startPoint.x1 + width * i + leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin],
- [startPoint.x1 + width * i + width + leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin],
- [startPoint.x1 + width * i + width + leftMargin, startRowPoint + tempMaxHeight * j + height + bottomMargin],
- [startPoint.x1 + width * i + leftMargin, startRowPoint + tempMaxHeight * j + height + bottomMargin],
- [startPoint.x1 + width * i + leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin],
- ]
-
- let squarePolygon = turf.polygon([square])
- let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1)
- let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] }))
-
- // if (disjointFromTrestle && isDisjoint) {
- moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id, moduleInfo: module }
- let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon })
- canvas?.add(tempModule)
- moduleSetupArray.push(tempModule)
- moduleGroup.push(tempModule)
- }
- }
- })
- }
-
- const flatRoofTopFlowSetupModule = (surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) => {
- checkedModule.forEach((module, index) => {
- const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
- const flowLines = getFlowLines(moduleSetupSurface, height)
- let startPoint = flowLines.top
-
- const maxLeftEndPoint = surfaceMaxLines.left.x1 //최 좌측
- const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측
- const maxBottomEndPoint = surfaceMaxLines.bottom.y1 //최하단
-
- let totalLeftEndPoint = maxLeftEndPoint - startPoint.x1
- let totalRightEndPoint = maxLeftEndPoint - maxRightEndPoint
- let totalBottomEndPoint = maxBottomEndPoint - startPoint.y1
- let diffLeftEndPoint = Math.abs(totalLeftEndPoint / width)
- let diffRightEndPoint = Math.ceil(Math.abs(totalRightEndPoint / width))
- let diffBottomEndPoint = Math.ceil(Math.abs(totalBottomEndPoint / height))
- let startColPoint = Math.abs(width * Math.ceil(diffLeftEndPoint) - startPoint.x1)
- let tempMaxWidth = width //최대배치인지 확인하려고 넣음
-
- for (let j = 0; j < diffBottomEndPoint; j++) {
- bottomMargin = marginHeight * j
- for (let i = 0; i < diffRightEndPoint; i++) {
- leftMargin = marginWidth * i
-
- square = [
- [startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 + height * j + bottomMargin],
- [startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 + height * j + height + bottomMargin],
- [startColPoint + tempMaxWidth * i + width + leftMargin, startPoint.y1 + height * j + height + bottomMargin],
- [startColPoint + tempMaxWidth * i + width + leftMargin, startPoint.y1 + height * j + bottomMargin],
- [startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 + height * j + bottomMargin],
- ]
-
- let squarePolygon = turf.polygon([square])
- let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1)
- let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] }))
-
- // if (disjointFromTrestle && isDisjoint) {
- moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id, moduleInfo: module }
- let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon })
- canvas?.add(tempModule)
- moduleSetupArray.push(tempModule)
- moduleGroup.push(tempModule)
- }
- }
- })
- }
-
- const flatRoofRightFlowSetupModule = (surfaceMaxLines, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) => {
- checkedModule.forEach((module, index) => {
- const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
- const flowLines = getFlowLines(moduleSetupSurface, width)
- let startPoint = flowLines.right
-
- const maxLeftEndPoint = surfaceMaxLines.left.x1 //최 좌측
- const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단
- const maxBottomEndPoint = surfaceMaxLines.bottom.y1 //최하단
-
- let totalTopEndPoint = Math.abs(maxTopEndPoint - startPoint.y1) //전체 높이에서 현재 높이를 뺌
- let diffTopEndPoint = Math.abs(totalTopEndPoint / height)
- let totalHeight = Math.ceil(Math.abs(maxBottomEndPoint - maxTopEndPoint) / height)
- let totalWidth = Math.abs(startPoint.x1 - maxLeftEndPoint) / width
- let startRowPoint = startPoint.y1 - height * Math.ceil(diffTopEndPoint) - 3 // -3으로 위치살짝 보정
- let tempMaxHeight = height //최대배치인지 확인하려고 넣음
-
- for (let i = 0; i <= totalWidth; i++) {
- bottomMargin = marginHeight * i
- for (let j = 0; j < totalHeight; j++) {
- leftMargin = marginWidth * j
-
- square = [
- [startPoint.x1 - width * i - leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin],
- [startPoint.x1 - width * i - width - leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin],
- [startPoint.x1 - width * i - width - leftMargin, startRowPoint + tempMaxHeight * j + height + bottomMargin],
- [startPoint.x1 - width * i - leftMargin, startRowPoint + tempMaxHeight * j + height + bottomMargin],
- [startPoint.x1 - width * i - leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin],
- ]
-
- let squarePolygon = turf.polygon([square])
- let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1)
- let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] }))
-
- // if (disjointFromTrestle && isDisjoint) {
- moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id, moduleInfo: module }
- let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon })
- canvas?.add(tempModule)
- moduleSetupArray.push(tempModule)
- moduleGroup.push(tempModule)
+
+ let disjointFromTrestle = checkModuleDisjointSurface(squarePolygon, polygonToTurfPolygon(moduleSetupSurface, true))
+ let isDisjoint = checkModuleDisjointObjects(squarePolygon, containsBatchObjects)
+
+ if (disjointFromTrestle && isDisjoint) {
+ //최초 한번은 그냥 그린다
+ //겹치는지 확인해서 포함된 모듈만 그린다
+ canvas?.add(tempModule)
+ moduleSetupArray.push(tempModule)
+ moduleArray.push(tempModule)
+ canvas.renderAll()
+
+ // ++installedModuleHeightCount
+
+ isInstall = true
+ //마지막에 설치된 모듈의 Y 좌표
+ installedLastHeightCoord = moduleY - height - heightMargin
+ } else {
+ //디버깅용
+ // tempModule.set({ fill: 'transparent', stroke: 'red', strokeWidth: 1 })
+ // canvas?.add(tempModule)
+ // canvas.renderAll()
+ }
+ }
+ if (isInstall) {
+ ++installedModuleHeightCount
}
}
+ setupModule.push(moduleArray)
})
}
@@ -2448,20 +2565,13 @@ export function useModuleBasicSetting(tabNum) {
const containsBatchObjects = objectsIncludeSurface(turfModuleSetupSurface) //배치면에 오브젝트(도머, 개구등)이 있는지 확인하는 로직
const surfaceMaxLines = findSetupSurfaceMaxLines(moduleSetupSurface)
- const marginWidth = 1
- const marginHeight = 3
+ const intvHor = 30
+ const intvVer = 10
canvas.renderAll()
- if (compasDeg >= 0 && compasDeg < 90) {
- flatRoofDownFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight)
- } else if (compasDeg >= 90 && compasDeg < 180) {
- flatRoofLeftFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight)
- } else if (compasDeg >= 180 && compasDeg < 270) {
- flatRoofRightFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight)
- } else {
- flatRoofTopFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight)
- }
+ //육지붕은 왼쪽 기준으로 그려진다
+ flatRoofDownFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, intvHor, intvVer, containsBatchObjects)
const setupedModules = moduleSetupArray.filter((module, index) => {
let disjointFromTrestle = checkModuleDisjointSurface(module.turfPoints, turfModuleSetupSurface)
@@ -2495,7 +2605,8 @@ export function useModuleBasicSetting(tabNum) {
})
moduleSetupSurface.set({ modules: setupedModules })
- getModuleStatistics()
+ setModuleStatisticsData()
+ // getModuleStatistics()
// console.log('moduleSetupSurface', moduleSetupSurface)
// console.log('setupedModules', setupedModules)
@@ -2543,62 +2654,6 @@ export function useModuleBasicSetting(tabNum) {
return isDisjoint
}
- const getModuleStatistics = () => {
- const surfaces = canvas.getObjects().filter((obj) => POLYGON_TYPE.MODULE_SETUP_SURFACE === obj.name)
- // console.log('🚀 ~ getModuleStatistics ~ surfaces:', surfaces)
- let totalWpout = 0
- let moduleInfo = {}
- const rows = surfaces.map((surface) => {
- let wpOut = 0
- moduleInfo = {}
- surface.modules.forEach((module) => {
- if (!moduleInfo[module.moduleInfo.itemId]) {
- moduleInfo[module.moduleInfo.itemId] = { name: module.moduleInfo.itemNm, amount: 0, id: module.moduleInfo.itemId }
- }
- wpOut += +module.moduleInfo.wpOut
-
- moduleInfo[module.moduleInfo.itemId].amount++
- })
- totalWpout += wpOut
- // console.log('🚀 ~ moduleData.rows=surfaces.map ~ module:', module)
- const rowObject = {}
- Object.keys(moduleInfo).forEach((key) => {
- rowObject[key] = moduleInfo[key].amount
- })
- return {
- ...rowObject, // 총 발전량 = 발전량 * 모듈 개수
- ...surface,
- name: canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].directionText, // 지붕면
- // powerGeneration: wpOut.toLocaleString('ko-KR', { maximumFractionDigits: 4 }),
- wpOut: (wpOut / 1000).toFixed(3),
- }
- })
-
- // console.log('🚀 ~ getModuleStatistics ~ rows:', rows)
- // console.log('🚀 ~ getModuleStatistics ~ moduleInfo:', moduleInfo)
- const header = [
- { name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'name' },
- ...Object.keys(moduleInfo).map((key) => {
- return { name: moduleInfo[key].name, prop: key }
- }),
- { name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`, prop: 'wpOut' },
- ]
- let footer = [getMessage('modal.panel.batch.statistic.total')]
- let footerData = {}
- rows.forEach((row) => {
- Object.keys(moduleInfo).map((key) => {
- if (!footerData[key]) footerData[key] = 0
- footerData[key] += row[key]
- })
- })
- Object.keys(footerData).forEach((key) => {
- footer.push(footerData[key])
- })
- footer.push((totalWpout / 1000).toFixed(3))
- // console.log({ header: header, rows, footer: footer })
- setModuleStatistics({ header: header, rows, footer: footer })
- }
-
/**
* 모듈의 너비와 높이를 계산하는 함수
* @param {object} maxLengthLine 최대 길이 라인
@@ -2622,7 +2677,7 @@ export function useModuleBasicSetting(tabNum) {
10
}
- return canvasSetting.roofSizeSet === '1'
+ return canvasSetting.roofSizeSet == '1'
? calculateVisibleModuleHeight(tmpWidth, tmpHeight, getDegreeByChon(moduleSetupSurface.roofMaterial.pitch), moduleSetupSurface.direction)
: { width: tmpWidth, height: tmpHeight }
}
diff --git a/src/hooks/module/useModuleSelection.js b/src/hooks/module/useModuleSelection.js
index 26bac8e8..8fa274a4 100644
--- a/src/hooks/module/useModuleSelection.js
+++ b/src/hooks/module/useModuleSelection.js
@@ -1,4 +1,4 @@
-import { useRecoilState, useRecoilValue } from 'recoil'
+import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import { useContext, useEffect, useState } from 'react'
import { GlobalDataContext } from '@/app/GlobalDataProvider'
import { useMasterController } from '@/hooks/common/useMasterController'
@@ -7,6 +7,8 @@ import { selectedModuleState, moduleSelectionInitParamsState, moduleSelectionDat
import { isObjectNotEmpty } from '@/util/common-utils'
import { canvasState } from '@/store/canvasAtom'
import { POLYGON_TYPE } from '@/common/common'
+import { moduleStatisticsState } from '@/store/circuitTrestleAtom'
+import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
export function useModuleSelection(props) {
const canvas = useRecoilValue(canvasState)
@@ -25,6 +27,9 @@ export function useModuleSelection(props) {
const [moduleSelectionInitParams, setModuleSelectionInitParams] = useRecoilState(moduleSelectionInitParamsState) //모듈 기본 데이터 ex) 면조도, 높이등등
const { getModuleTypeItemList } = useMasterController()
const { findCommonCode } = useCommonCode()
+ const resetStatisticsData = useResetRecoilState(moduleStatisticsState)
+
+ const { restoreModuleInstArea } = useModuleBasicSetting()
const bindInitData = () => {
setInstallHeight(managementState?.installHeight)
@@ -89,16 +94,9 @@ export function useModuleSelection(props) {
getModuleData(roofsIds)
- //해당 메뉴 이동시 배치면 삭제
- const moduleSurfacesArray = canvas
- .getObjects()
- .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE || obj.name === POLYGON_TYPE.MODULE || obj.name === POLYGON_TYPE.OBJECT_SURFACE)
- if (moduleSurfacesArray.length > 0) {
- moduleSurfacesArray.forEach((moduleSurface) => {
- canvas.remove(moduleSurface)
- })
- canvas.renderAll()
- }
+ //모듈설치면 초기화
+ restoreModuleInstArea()
+ resetStatisticsData()
}, [])
const getModuleData = async (roofsIds) => {
diff --git a/src/hooks/module/useModuleTabContents.js b/src/hooks/module/useModuleTabContents.js
index a7516cf1..f6c46314 100644
--- a/src/hooks/module/useModuleTabContents.js
+++ b/src/hooks/module/useModuleTabContents.js
@@ -1,5 +1,5 @@
import { useEffect, useState, useRef } from 'react'
-import { useRecoilValue, useRecoilState } from 'recoil'
+import { useRecoilValue, useRecoilState, useResetRecoilState } from 'recoil'
import { pitchTextSelector } from '@/store/canvasAtom'
import { useMasterController } from '@/hooks/common/useMasterController'
import { useCommonCode } from '@/hooks/common/useCommonCode'
@@ -53,8 +53,6 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
const hajebichiRef = useRef()
const lengthRef = useRef()
- const [isChangeInitData, setIsChangeInitData] = useState(false)
-
//서까래간격 변경
const handleChangeRaftBase = (option) => {
setSelectedRaftBase({ raftBaseCd: option.clCode, clCode: option.clCode })
@@ -419,12 +417,6 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
//공법 리스트 초기화
setConstructionList([])
- // 기본 정보 초기화
- setModuleSelectionData({
- ...moduleSelectionData,
- roofConstructions: [],
- })
-
// 선택 데이터 초 기화
setModuleConstructionSelectionData({
addRoof: addRoof,
@@ -437,14 +429,13 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
//임시 데이터 초기화
setTempModuleSelectionData({
...moduleSelectionData,
- roofConstructions: tempRoofConstructions,
+ roofConstructions: num === 2 ? [] : tempRoofConstructions,
})
//처마커버 해제
setCvrChecked(false)
//눈막이금구 해제
setSnowGdChecked(false)
-
// 데이터 없음으로 변경
setIsExistData(false)
diff --git a/src/hooks/module/useOrientation.js b/src/hooks/module/useOrientation.js
index 9e57c687..649d8f79 100644
--- a/src/hooks/module/useOrientation.js
+++ b/src/hooks/module/useOrientation.js
@@ -27,6 +27,13 @@ export function useOrientation() {
setCompasDeg(0)
}
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
+ const hasModules = canvas.getObjects().some((obj) => obj.name === 'module')
+ if (!hasModules) {
+ roofs.forEach((roof) => {
+ delete roof.directionText
+ })
+ }
+
roofs.forEach((roof) => {
roof.set({
moduleCompass: isNaN(compasDeg) ? 0 : compasDeg,
diff --git a/src/hooks/module/useTrestle.js b/src/hooks/module/useTrestle.js
index 3f52f0ca..48ad5913 100644
--- a/src/hooks/module/useTrestle.js
+++ b/src/hooks/module/useTrestle.js
@@ -1,6 +1,6 @@
import { useRecoilValue } from 'recoil'
import { canvasState, currentAngleTypeSelector } from '@/store/canvasAtom'
-import { POLYGON_TYPE } from '@/common/common'
+import { POLYGON_TYPE, TRESTLE_MATERIAL } from '@/common/common'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { getDegreeByChon } from '@/util/canvas-util'
import { v4 as uuidv4 } from 'uuid'
@@ -9,6 +9,7 @@ import { basicSettingState, trestleDisplaySelector } from '@/store/settingAtom'
import { useSwal } from '@/hooks/useSwal'
import { useContext } from 'react'
import { QcastContext } from '@/app/QcastProvider'
+import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle'
// 모듈간 같은 행, 열의 마진이 10 이하인 경우는 같은 행, 열로 간주
const MODULE_MARGIN = 10
@@ -22,12 +23,16 @@ export const useTrestle = () => {
const isTrestleDisplay = useRecoilValue(trestleDisplaySelector)
const { swalFire } = useSwal()
const { setIsGlobalLoading } = useContext(QcastContext)
+
+ const { getSelectedPcsItemList } = useCircuitTrestle()
+ const { resetCircuits } = useCircuitTrestle()
+
const apply = () => {
const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit)
if (notAllocationModules.length > 0) {
swalFire({ text: '回路番号が設定されていないモジュールがあります。 番号を設定しなおすか、 パネルを削除してください。', icon: 'error' })
setIsGlobalLoading(false)
- return null
+ return
}
try {
//처마력바가 체크되어 있는 경우 exposedBottomPoints를 이용해 처마력바 그려줘야함.
@@ -48,9 +53,12 @@ export const useTrestle = () => {
surfaces.forEach((surface) => {
const parent = canvas.getObjects().find((obj) => obj.id === surface.parentId)
const roofMaterialIndex = parent.roofMaterial.index
+ if (+roofSizeSet === 3) {
+ return
+ }
const construction = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex).construction
if (!construction) {
- alert('앞에서 셋팅 안됨')
+ swalFire({ text: 'construction 존재안함', icon: 'error' })
return
}
@@ -75,6 +83,7 @@ export const useTrestle = () => {
})
}
+ // 모듈들의 centerPoint들을 이용해 각 모듈의 정보(가장 아랫라인 모듈, 가장 윗라인 모듈, 접면, 반접면 등 계산)
const result = calculateForApi(surface)
if (!result) {
@@ -119,11 +128,10 @@ export const useTrestle = () => {
rightExposedHalfBottomPoints.length > 0 ||
leftExposedHalfTopModules.length > 0 ||
rightExposedHalfTopPoints.length > 0
-
surface.isChidory = isChidory
if (plvrYn === 'N' && isChidory) {
- alert('치조불가공법입니다.')
+ swalFire({ text: '치조불가공법입니다.', icon: 'error' })
clear()
throw new Error('치조불가공법입니다.')
}
@@ -144,7 +152,7 @@ export const useTrestle = () => {
if (!bottomPoints) return
const eaveBar = new fabric.Line([bottomPoints[0].x, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[1].y], {
parent: surface,
- name: 'eaveBar',
+ name: TRESTLE_MATERIAL.EAVE_BAR,
stroke: 'blue',
strokeWidth: 4,
selectable: false,
@@ -175,7 +183,7 @@ export const useTrestle = () => {
if (!bottomPoints) return
const halfEaveBar = new fabric.Line(barPoints, {
parent: surface,
- name: 'halfEaveBar',
+ name: TRESTLE_MATERIAL.HALF_EAVE_BAR,
stroke: 'blue',
strokeWidth: 4,
selectable: false,
@@ -205,7 +213,7 @@ export const useTrestle = () => {
if (!bottomPoints) return
const halfEaveBar = new fabric.Line(barPoints, {
parent: surface,
- name: 'halfEaveBar',
+ name: TRESTLE_MATERIAL.HALF_EAVE_BAR,
stroke: 'blue',
strokeWidth: 4,
selectable: false,
@@ -595,22 +603,25 @@ export const useTrestle = () => {
const quotationParam = getTrestleParams(surface, exposedBottomModules)
- surface.set({ quotationParam, isComplete: true })
+ surface.set({ quotationParam })
})
- return setEstimateData()
+ return true
} catch (e) {
// 에러 발생시 가대 초기화
console.error(e)
- // clear()
+ clear()
setViewCircuitNumberTexts(true)
setIsGlobalLoading(false)
- return null
+ return false
}
}
//module Rack 정보를 얻기위한 데이터 가공
function moduleTransformData(arr) {
+ //arr의 moduleTpCd를 이용하여 정렬
+ arr = arr.sort((a, b) => a.moduleTpCd.localeCompare(b.moduleTpCd))
+
let counts = {}
arr.forEach((item) => {
@@ -624,18 +635,18 @@ export const useTrestle = () => {
}
// itemList 조회 후 estimateParam에 저장
- const setEstimateData = async () => {
+ const getEstimateData = async () => {
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
//surfaces.pcses들을 배열로 묶는다
const pcses = surfaces[0].pcses.filter((pcs) => pcs !== null && pcs !== undefined)
- surfaces.forEach((surface, index) => {
- if (index !== 0) {
- if (surface.pcses) {
- pcses.concat(surface.pcses)
- }
- }
- })
+ // surfaces.forEach((surface, index) => {
+ // if (index !== 0) {
+ // if (surface.pcses) {
+ // pcses.concat(surface.pcses)
+ // }
+ // }
+ // })
const allModules = surfaces.map((surface) => surface.modules).flat()
// 모듈 파라미터 생성
@@ -653,17 +664,18 @@ export const useTrestle = () => {
//견적서 itemList 조회
const { data, data2, result } = await getQuotationItem(params)
- let itemList
- if (!data) {
- return
- }
- itemList = data
if (result.resultCode === 'E') {
swalFire({ text: result.resultMsg, icon: 'error' })
- return null
+ return
}
+ let itemList
+ if (!data || data.length === 0) {
+ return
+ }
+ itemList = data
+
//northArrangement 북면 설치 여부
const northArrangement = getNorthArrangement()
// circuitItemList의 경우는 moduleList에서 circuitId만 groupBy한다.
@@ -672,18 +684,22 @@ export const useTrestle = () => {
// roofSurfaceList 생성
const roofSurfaceList = surfaces.map((surface) => {
const parent = canvas.getObjects().find((obj) => obj.id === surface.parentId)
- const { directionText, roofMaterial, pitch: slope, moduleCompass, surfaceCompass } = parent
+ const { directionText, roofMaterial, moduleCompass, surfaceCompass } = parent
+ const slope = Number(roofMaterial.pitch)
const roofMaterialIndex = parent.roofMaterial.index
const { nameJp: roofMaterialIdMulti } = roofMaterial
const moduleSelection = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex)
- const { constTp: constructSpecification, constTpJp: constructSpecificationMulti } = moduleSelection.construction
- const {
- trestleMkrCd,
- constMthdCd: supportMethodId,
- roofBaseCd,
- trestleMkrCdJp: supportMeaker,
- constMthdCdJp: supportMethodIdMulti,
- } = moduleSelection.trestle
+ let construction = moduleSelection?.construction
+ let constructSpecification = +roofSizeSet === 3 ? null : construction.constTp
+ let constructSpecificationMulti = +roofSizeSet === 3 ? null : construction.constTpJp
+
+ const trestle = moduleSelection?.trestle
+
+ let trestleMkrCd = +roofSizeSet === 3 ? null : trestle.trestleMkrCd
+ let supportMethodId = +roofSizeSet === 3 ? null : trestle.constMthdCd
+ let roofBaseCd = +roofSizeSet === 3 ? null : trestle.roofBaseCd
+ let supportMeaker = +roofSizeSet === 3 ? null : trestle.trestleMkrCdJp
+ let supportMethodIdMulti = +roofSizeSet === 3 ? null : trestle.constMthdCdJp
const modules = surface.modules
const moduleList = modules.map((module) => {
@@ -698,32 +714,94 @@ export const useTrestle = () => {
return {
roofSurfaceId: surface.id,
roofSurface: directionText.replace(/[0-9]/g, ''),
- roofMaterialId: roofMaterial.roofMatlCd,
+ roofMaterialId: +roofSizeSet === 3 ? '陸屋根' : roofMaterial.roofMatlCd, // 육지붕의 경우 지붕재 ID 값이 없기 때문에 임의 값 지정
supportMethodId,
constructSpecification,
constructSpecificationMulti,
- roofMaterialIdMulti,
+ roofMaterialIdMulti: +roofSizeSet === 3 ? '陸屋根' : roofMaterialIdMulti,
supportMethodIdMulti,
supportMeaker,
- slope,
+ slope: +roofSizeSet === 3 ? 0 : slope,
classType: currentAngleType === 'slope' ? '0' : '1',
- angle: getDegreeByChon(slope),
- azimuth: surfaceCompass ?? moduleCompass ?? 0,
+ angle: +roofSizeSet === 3 ? 0 : getDegreeByChon(slope),
+ azimuth: getAzimuth(parent),
moduleList,
}
})
// circuitItemList 중복제거
circuitItemList = circuitItemList.filter((item, index) => circuitItemList.indexOf(item) === index)
- circuitItemList = circuitItemList.map((circuitId) => {
- return {
- itemId: circuitId,
- }
- })
+ circuitItemList = getSelectedPcsItemList()
return { itemList, northArrangement, roofSurfaceList, circuitItemList }
}
+ // 발전 시뮬레이션 용 각도 재계산
+ const getAzimuth = (parent) => {
+ const { moduleCompass, surfaceCompass, direction } = parent
+
+ if (surfaceCompass) {
+ if (surfaceCompass > 180) {
+ return surfaceCompass - 360
+ }
+ return surfaceCompass
+ }
+
+ switch (direction) {
+ case 'south': {
+ if (moduleCompass < 0) {
+ return -1 * moduleCompass
+ } else if (moduleCompass === 0) {
+ return 0
+ } else if (moduleCompass < 180) {
+ return -1 * moduleCompass
+ } else if (moduleCompass === 180) {
+ return 180
+ }
+ }
+ case 'north': {
+ if (moduleCompass < 0) {
+ return -1 * (180 + moduleCompass)
+ } else if (moduleCompass === 0) {
+ return 180
+ } else if (moduleCompass < 180) {
+ return 180 - moduleCompass
+ } else if (moduleCompass === 180) {
+ return 0
+ }
+ }
+ case 'west': {
+ if (moduleCompass > -180 && moduleCompass < -90) {
+ return -180 - (90 + moduleCompass)
+ } else if (moduleCompass < 0) {
+ return 180 - (90 + moduleCompass)
+ } else if (moduleCompass === 0) {
+ return 90
+ } else if (moduleCompass < 180) {
+ return 90 - moduleCompass
+ } else if (moduleCompass === 180) {
+ return -90
+ }
+ }
+ case 'east': {
+ if (moduleCompass < 0) {
+ return -(90 + moduleCompass)
+ } else if (moduleCompass === 0) {
+ return -90
+ } else if (moduleCompass < 90) {
+ return -180 + (90 - moduleCompass)
+ } else if (moduleCompass < 180) {
+ return 180 + (90 - moduleCompass)
+ } else if (moduleCompass === 180) {
+ return 90
+ }
+ }
+ }
+
+ return 0
+ }
+
+ // 북면설치가 한개라도 되어있는지 확인
const getNorthArrangement = () => {
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
let northArrangement = '0'
@@ -742,6 +820,7 @@ export const useTrestle = () => {
return northArrangement
}
+ // 다음 윗 모듈을 찾는다.
const findNextModule = (currentPoint, centerPoints, direction) => {
let { x, y, horizontal, vertical } = { ...currentPoint }
let { widthArr, heightArr } = centerPoints[0]
@@ -788,6 +867,7 @@ export const useTrestle = () => {
return result
}
+ // 다음 왼쪽 모듈을 찾는다.
const findNextLeftModule = (currentPoint, centerPoints, direction) => {
let { x, y, horizontal, vertical } = { ...currentPoint }
let { widthArr, heightArr } = centerPoints[0]
@@ -851,6 +931,8 @@ export const useTrestle = () => {
return result
}
+
+ // 다음 오른쪽 모듈을 찾는다.
const findNextRightModule = (currentPoint, centerPoints, direction) => {
let { x, y, horizontal, vertical } = { ...currentPoint }
let { widthArr, heightArr } = centerPoints[0]
@@ -910,12 +992,20 @@ export const useTrestle = () => {
return result
}
+ // rack을 그린다.
const drawRacks = (rackInfos, rackQty, rackIntvlPct, module, direction, l, rackYn) => {
- if (!rackInfos) {
- return
- }
const { width, height, left, top, lastX, lastY, surfaceId } = module
const surface = canvas.getObjects().find((obj) => obj.id === surfaceId)
+ if (!rackInfos) {
+ const maxRows = surface.trestleDetail.moduleMaxRows
+ const maxCols = surface.trestleDetail.moduleMaxCols
+ const msg = `選択した家で設置可能
+モジュールの最大段数は${maxRows}、最大列数は${maxCols}です。
+上限より上部に取り付けたモジュールを削除してください。`
+ swalFire({ title: msg, type: 'alert' })
+ throw new Error('rackInfos is null')
+ }
+
const roof = canvas.getObjects().find((obj) => obj.id === surface.parentId)
const degree = getDegreeByChon(roof.roofMaterial.pitch)
@@ -1008,7 +1098,7 @@ export const useTrestle = () => {
rackLength = getTrestleLength(setRackTpLen, degree) / 10
if (setRackTpCd === 'RACK') {
const rack = new fabric.Line([startPointX, startPointY, startPointX, startPointY - rackLength], {
- name: 'smartRack',
+ name: TRESTLE_MATERIAL.SMART_RACK,
stroke: 'red',
strokeWidth: 4,
selectable: true,
@@ -1039,7 +1129,7 @@ export const useTrestle = () => {
})
} else {
const rack = new fabric.Line([startPointX, startPointY, startPointX, startPointY - rackLength], {
- name: 'rack',
+ name: TRESTLE_MATERIAL.RACK,
stroke: 'red',
strokeWidth: 4,
selectable: false,
@@ -1081,7 +1171,7 @@ export const useTrestle = () => {
rackLength = getTrestleLength(setRackTpLen, degree) / 10
if (setRackTpCd === 'RACK') {
const rack = new fabric.Line([startPointX, startPointY, startPointX - rackLength, startPointY], {
- name: 'smartRack',
+ name: TRESTLE_MATERIAL.SMART_RACK,
stroke: 'red',
strokeWidth: 4,
selectable: false,
@@ -1112,7 +1202,7 @@ export const useTrestle = () => {
})
} else {
const rack = new fabric.Line([startPointX, startPointY, startPointX - rackLength, startPointY], {
- name: 'rack',
+ name: TRESTLE_MATERIAL.RACK,
stroke: 'red',
shadow: {
color: 'black', // Outline color
@@ -1153,7 +1243,7 @@ export const useTrestle = () => {
rackLength = getTrestleLength(setRackTpLen, degree) / 10
if (setRackTpCd === 'RACK') {
const rack = new fabric.Line([startPointX, startPointY, startPointX + rackLength, startPointY], {
- name: 'smartRack',
+ name: TRESTLE_MATERIAL.SMART_RACK,
stroke: 'red',
strokeWidth: 4,
selectable: false,
@@ -1184,7 +1274,7 @@ export const useTrestle = () => {
})
} else {
const rack = new fabric.Line([startPointX, startPointY, startPointX + rackLength, startPointY], {
- name: 'rack',
+ name: TRESTLE_MATERIAL.RACK,
stroke: 'red',
shadow: {
color: 'black', // Outline color
@@ -1223,7 +1313,7 @@ export const useTrestle = () => {
rackLength = getTrestleLength(setRackTpLen, degree) / 10
if (setRackTpCd === 'RACK') {
const rack = new fabric.Line([startPointX, startPointY, startPointX, startPointY + rackLength], {
- name: 'smartRack',
+ name: TRESTLE_MATERIAL.SMART_RACK,
stroke: 'red',
strokeWidth: 4,
selectable: false,
@@ -1254,7 +1344,7 @@ export const useTrestle = () => {
})
} else {
const rack = new fabric.Line([startPointX, startPointY, startPointX, startPointY + rackLength], {
- name: 'rack',
+ name: TRESTLE_MATERIAL.RACK,
stroke: 'red',
shadow: {
color: 'black', // Outline color
@@ -1285,6 +1375,7 @@ export const useTrestle = () => {
}
}
+ //파라미터로 받은 배치면의 rack을 가지고 지지금구를 그린다.
const installBracket = (surface) => {
const modules = surface.modules
const racks = []
@@ -1315,7 +1406,7 @@ export const useTrestle = () => {
left: x2 - bracketLength / 3,
top: len,
fill: 'green',
- name: 'bracket',
+ name: TRESTLE_MATERIAL.BRACKET,
parentId: rack.parentId,
visible: isTrestleDisplay,
surfaceId: surface.id,
@@ -1337,7 +1428,7 @@ export const useTrestle = () => {
left: len,
top: y2 - bracketLength / 3,
fill: 'green',
- name: 'bracket',
+ name: TRESTLE_MATERIAL.BRACKET,
parentId: rack.parentId,
visible: isTrestleDisplay,
surfaceId: surface.id,
@@ -1362,7 +1453,7 @@ export const useTrestle = () => {
parentId: rack.parentId,
visible: isTrestleDisplay,
surfaceId: surface.id,
- name: 'bracket',
+ name: TRESTLE_MATERIAL.BRACKET,
width: bracketLength,
height: bracketLength,
selectable: false,
@@ -1380,7 +1471,7 @@ export const useTrestle = () => {
left: x2 - bracketLength / 3,
top: len,
fill: 'green',
- name: 'bracket',
+ name: TRESTLE_MATERIAL.BRACKET,
parentId: rack.parentId,
visible: isTrestleDisplay,
surfaceId: surface.id,
@@ -1483,6 +1574,7 @@ export const useTrestle = () => {
}
}
+ // 랙 없음의 지지금구를 그린다.
const drawBracketWithOutRack = (module, rackIntvlPct, count, l, direction, moduleIntvlHor, moduleIntvlVer) => {
let { width, height, left, top } = module
let startPointX
@@ -1560,12 +1652,31 @@ export const useTrestle = () => {
}
}
+ switch (direction) {
+ case 'south': {
+ startPointY -= 5
+ break
+ }
+ case 'east': {
+ startPointX -= 5
+ break
+ }
+ case 'west': {
+ startPointX -= 5
+ break
+ }
+ case 'north': {
+ startPointY -= 5
+ break
+ }
+ }
+
for (let i = 0; i < count; i++) {
const bracket = new fabric.Rect({
- left: startPointX - 5,
- top: startPointY - 5,
+ left: startPointX,
+ top: startPointY,
fill: 'green',
- name: 'bracket',
+ name: TRESTLE_MATERIAL.BRACKET,
parentId: module.id,
surfaceId: module.surfaceId,
width: 10,
@@ -1575,14 +1686,15 @@ export const useTrestle = () => {
})
canvas.add(bracket)
canvas.renderAll()
+ const maxIntvl = Math.max(moduleIntvlHor, moduleIntvlVer)
if (direction === 'south') {
- startPointY -= height
+ startPointY -= height + maxIntvl / 10
} else if (direction === 'north') {
- startPointY += height
+ startPointY += height + maxIntvl / 10
} else if (direction === 'east') {
- startPointX -= width
+ startPointX -= width + maxIntvl / 10
} else if (direction === 'west') {
- startPointX += width
+ startPointX += width + maxIntvl / 10
}
}
}
@@ -1641,7 +1753,7 @@ export const useTrestle = () => {
const { width, height } = { ...module }
widthArr.push(width)
heightArr.push(height)
- centerPoints.push({ x, y, width: Math.floor(width), height: Math.floor(height), index, moduleInfo: module.moduleInfo })
+ centerPoints.push({ x, y, width: Math.floor(width), height: Math.floor(height), index, moduleInfo: module.moduleInfo, module })
})
//widthArr 중복 제거 1이상 차이가 나지 않으면 같은 너비로 간주
@@ -1715,7 +1827,13 @@ export const useTrestle = () => {
let rightExposedHalfTopPoints = []
centerPoints.forEach((centerPoint, index) => {
- let { x, y, width, height, widthArr, heightArr } = { ...centerPoint }
+ let { x, y, width, height, widthArr, heightArr, module } = { ...centerPoint }
+
+ /* 디버깅용
+ const originFill = module.fill
+ module.set('fill', 'red')
+ canvas.renderAll()*/
+
// centerPoints중에 현재 centerPoint와 x값이 같고, y값이 y-height값과 같은 centerPoint가 있는지 확인
let bottomCell
let bottomLeftPoint
@@ -1805,7 +1923,12 @@ export const useTrestle = () => {
break
}
+ /**
+ * 디버깅용
+ module.set('fill', originFill)
+ canvas.renderAll()
+ */
if (bottomCell) {
return
}
@@ -1822,13 +1945,18 @@ export const useTrestle = () => {
}
} else if (leftBottomCnt + rightBottomCnt === 0) {
exposedBottomPoints.push(centerPoint)
+ } else if (leftBottomCnt + rightBottomCnt === 2) {
+ touchDimension++
}
})
// 노출상면 및 접면 체크
centerPoints.forEach((centerPoint, index) => {
- let { x, y, width, height, widthArr, heightArr } = { ...centerPoint }
-
+ let { x, y, width, height, widthArr, heightArr, module } = { ...centerPoint }
+ const originFill = module.fill
+ /* 디버깅용
+ module.set('fill', 'blue')
+ canvas.renderAll()*/
let topCell
let topLeftPoint
let topRightPoint
@@ -1841,7 +1969,8 @@ export const useTrestle = () => {
height = height + vertical
heightArr.forEach((h) => {
if (topCell) return
- topCell = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y + h)) < maxY)
+ topCell = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y - h)) < maxY)
+
if (leftTopCnt === 0) {
topLeftPoint = { x: x - width / 2, y: y - h }
leftTopCnt = centerPoints.filter(
@@ -1860,7 +1989,7 @@ export const useTrestle = () => {
height = height + vertical
heightArr.forEach((h) => {
if (topCell) return
- topCell = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y - h)) < maxY)
+ topCell = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y + h)) < maxY)
if (leftTopCnt === 0) {
topLeftPoint = { x: x + width / 2, y: y + h }
leftTopCnt = centerPoints.filter(
@@ -1879,7 +2008,7 @@ export const useTrestle = () => {
width = width + horizontal
widthArr.forEach((w) => {
if (topCell) return
- topCell = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x + w)) < maxX && Math.abs(centerPoint.y - y) < maxY)
+ topCell = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x - w)) < maxX && Math.abs(centerPoint.y - y) < maxY)
if (leftTopCnt === 0) {
topLeftPoint = { x: x - w, y: y + height / 2 }
leftTopCnt = centerPoints.filter(
@@ -1899,7 +2028,7 @@ export const useTrestle = () => {
width = width + horizontal
widthArr.forEach((w) => {
if (topCell) return
- topCell = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x - w)) < maxX && Math.abs(centerPoint.y - y) < maxY)
+ topCell = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x + w)) < maxX && Math.abs(centerPoint.y - y) < maxY)
if (leftTopCnt === 0) {
topLeftPoint = { x: x + w, y: y - height / 2 }
leftTopCnt = centerPoints.filter(
@@ -1921,6 +2050,13 @@ export const useTrestle = () => {
return
}
+ /**
+ * 디버깅 용
+
+ module.set('fill', originFill)
+ canvas.renderAll()
+ */
+
if (leftTopCnt + rightTopCnt === 2) {
touchDimension++
return
@@ -2068,6 +2204,18 @@ export const useTrestle = () => {
rackRows: rack.rackRowsCd,
}
})
+
+ let smartRackParams = Object.values(smartRackGroup).map((smartRack, index) => {
+ return {
+ seq: index,
+ itemId: smartRack[0].rackId,
+ rackFittingCnt: smartRack[0].supFitQty,
+ rackRows: smartRack[0].rackRowsCd,
+ }
+ })
+
+ rackParams = [...rackParams, ...smartRackParams]
+
const parent = canvas.getObjects().find((obj) => obj.id === surface.parentId)
const roofMaterialIndex = parent.roofMaterial.index
const moduleSelection = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex)
@@ -2084,7 +2232,7 @@ export const useTrestle = () => {
moduleTpCd: module.itemTp,
roofMatlCd: parent.roofMaterial.roofMatlCd,
mixMatlNo: module.mixMatlNo,
- raftBaseCd: addRoof.raft,
+ raftBaseCd: addRoof.raft ?? addRoof.raftBaseCd,
inclCd: addRoof.pitch,
roofPitch: !addRoof.roofPchBase ? addRoof.roofPchBase : Number(addRoof.roofPchBase),
exposedLowerBottomTotCnt: result.exposedBottom, // 노출 최하면 갯수
@@ -2352,6 +2500,9 @@ export const useTrestle = () => {
if ((rightModule && !leftModule) || (!rightModule && leftModule)) {
// 둘중 하나가 없는경우는 처마커버 노출 추가
moduleRowResultData.exposedSideEavesCnt++
+ } else if (!rightModule && !leftModule) {
+ // 양쪽 둘다 없는경우는 처마커버 노출 2개 추가
+ moduleRowResultData.exposedSideEavesCnt += 2
}
}
}
@@ -2686,6 +2837,7 @@ export const useTrestle = () => {
canvas.remove(obj)
}
})
+ resetCircuits()
}
// 전모듈 의 회로번호 visible false 처리
@@ -2698,5 +2850,19 @@ export const useTrestle = () => {
canvas.renderAll()
}
- return { apply, getTrestleParams, clear, setViewCircuitNumberTexts }
+ // 가대 설치 완료 전,후 모든 surface의 isComplete를 변경
+ const setAllModuleSurfaceIsComplete = (bool) => {
+ const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
+ surfaces.forEach((surface) => {
+ surface.isComplete = bool
+ })
+ }
+
+ // 배치면 전체에 가대 설치 여부
+ const isAllComplete = () => {
+ const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
+ return surfaces.every((surface) => surface.isComplete)
+ }
+
+ return { apply, getTrestleParams, clear, setViewCircuitNumberTexts, getEstimateData, setAllModuleSurfaceIsComplete, isAllComplete }
}
diff --git a/src/hooks/object/useObjectBatch.js b/src/hooks/object/useObjectBatch.js
index ff446673..322f2531 100644
--- a/src/hooks/object/useObjectBatch.js
+++ b/src/hooks/object/useObjectBatch.js
@@ -1,11 +1,19 @@
'use client'
-import { useEffect } from 'react'
+import { useEffect, useRef } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom'
import { BATCH_TYPE, INPUT_TYPE, POLYGON_TYPE } from '@/common/common'
import { useEvent } from '@/hooks/useEvent'
-import { pointsToTurfPolygon, polygonToTurfPolygon, rectToPolygon, triangleToPolygon } from '@/util/canvas-util'
+import {
+ pointsToTurfPolygon,
+ polygonToTurfPolygon,
+ rectToPolygon,
+ triangleToPolygon,
+ getDegreeByChon,
+ toFixedWithoutRounding,
+ getTrianglePoints,
+} from '@/util/canvas-util'
import { useSwal } from '@/hooks/useSwal'
import * as turf from '@turf/turf'
import { usePolygon } from '@/hooks/usePolygon'
@@ -13,6 +21,8 @@ import { QPolygon } from '@/components/fabric/QPolygon'
import { v4 as uuidv4 } from 'uuid'
import { fontSelector } from '@/store/fontAtom'
import { useRoofFn } from '@/hooks/common/useRoofFn'
+import { roofDisplaySelector } from '@/store/settingAtom'
+import { usePopup } from '@/hooks/usePopup'
export function useObjectBatch({ isHidden, setIsHidden }) {
const { getMessage } = useMessage()
@@ -20,9 +30,11 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
const { addCanvasMouseEventListener, initEvent, addDocumentEventListener } = useEvent()
// const { addCanvasMouseEventListener, initEvent, addDocumentEventListener } = useContext(EventContext)
const { swalFire } = useSwal()
- const { drawDirectionArrow } = usePolygon()
+ const { drawDirectionArrow, addPolygon, addLengthText } = usePolygon()
const { setSurfaceShapePattern } = useRoofFn()
const lengthTextFont = useRecoilValue(fontSelector('lengthText'))
+ const roofDisplay = useRecoilValue(roofDisplaySelector)
+ const { closePopup } = usePopup()
useEffect(() => {
if (canvas) {
@@ -71,13 +83,15 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
}
}
- const applyOpeningAndShadow = (objectPlacement, buttonAct, surfaceShapePolygons) => {
+ const applyOpeningAndShadow = (objectPlacement, buttonAct) => {
const selectedType = objectPlacement.typeRef.current.find((radio) => radio.checked).value
const isCrossChecked = buttonAct === 1 ? objectPlacement.isCrossRef.current.checked : false
const objName = buttonAct === 1 ? BATCH_TYPE.OPENING : BATCH_TYPE.SHADOW
+ const surfaceShapePolygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
const objTempName = buttonAct === 1 ? BATCH_TYPE.OPENING_TEMP : BATCH_TYPE.SHADOW_TEMP
let rect, isDown, origX, origY
+
let selectedSurface
//프리입력
@@ -148,12 +162,15 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
const rectPolygon = pointsToTurfPolygon(rectToPolygon(rect))
const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
- //지붕 밖으로 그렸을때
- if (!turf.booleanWithin(rectPolygon, selectedSurfacePolygon)) {
- swalFire({ text: getMessage('batch.object.outside.roof'), icon: 'error' })
- //일단 지워
- deleteTempObjects()
- return
+ //그림자는 배치면이 겹친부분에도 그려져야 한다
+ if (rect.name === BATCH_TYPE.OPENING_TEMP) {
+ //지붕 밖으로 그렸을때
+ if (!turf.booleanWithin(rectPolygon, selectedSurfacePolygon)) {
+ swalFire({ text: getMessage('batch.object.outside.roof'), icon: 'error' })
+ //일단 지워
+ deleteTempObjects()
+ return
+ }
}
if (!isCrossChecked) {
@@ -230,12 +247,15 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
const rectPolygon = pointsToTurfPolygon(rectToPolygon(rect))
const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
- //지붕 밖으로 그렸을때
- if (!turf.booleanWithin(rectPolygon, selectedSurfacePolygon)) {
- swalFire({ text: getMessage('batch.object.outside.roof'), icon: 'error' })
- //일단 지워
- deleteTempObjects()
- return
+ //그림자는 배치면이 겹친부분에도 그려져야 한다
+ if (rect.name === BATCH_TYPE.OPENING_TEMP) {
+ //지붕 밖으로 그렸을때
+ if (!turf.booleanWithin(rectPolygon, selectedSurfacePolygon)) {
+ swalFire({ text: getMessage('batch.object.outside.roof'), icon: 'error' })
+ //일단 지워
+ deleteTempObjects()
+ return
+ }
}
if (!isCrossChecked) {
@@ -267,26 +287,17 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
* @param {*} surfaceShapePolygons
* @returns
*/
- const applyDormers = (dormerPlacement, buttonAct, surfaceShapePolygons) => {
+ const applyDormers = ({ height, width, pitch, offsetRef, offsetWidthRef, directionRef }, buttonAct) => {
const dormerName = buttonAct === 3 ? BATCH_TYPE.TRIANGLE_DORMER : BATCH_TYPE.PENTAGON_DORMER
const dormerTempName = buttonAct === 3 ? BATCH_TYPE.TRIANGLE_DORMER_TEMP : BATCH_TYPE.PENTAGON_DORMER_TEMP
- const height = dormerPlacement.heightRef.current !== null ? dormerPlacement.heightRef.current.value / 10 : 0
- const width = dormerPlacement.widthRef.current !== null ? dormerPlacement.widthRef.current.value / 10 : 0 //triangle일때는 없음
- const pitch = dormerPlacement.pitchRef.current !== null ? dormerPlacement.pitchRef.current.value : 0
- const offsetRef =
- dormerPlacement.offsetRef.current !== null
- ? dormerPlacement.offsetRef.current.value === ''
- ? 0
- : parseInt(dormerPlacement.offsetRef.current.value) / 10
- : 0
- const offsetWidthRef =
- dormerPlacement.offsetWidthRef.current !== null
- ? dormerPlacement.offsetWidthRef.current.value === ''
- ? 0
- : parseInt(dormerPlacement.offsetWidthRef.current.value) / 10
- : 0
- const directionRef = dormerPlacement.directionRef.current
+
+ //도머의 각도
+ const dormerAngle = getDegreeByChon(pitch)
+
let dormer, dormerOffset, isDown, selectedSurface, pentagonPoints, pentagonOffsetPoints
+
+ const surfaceShapePolygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
+
const id = uuidv4()
if (height === '' || pitch === '' || height <= 0 || pitch <= 0) {
@@ -294,10 +305,24 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
return
}
+ let theta = 0
+
+ let bottomLength = 0,
+ bottomOffsetLength = 0,
+ planeHypotenuse = 0,
+ planeOffsetHypotenuse = 0,
+ actualBottomLength = 0,
+ actualBottomOffsetLength = 0,
+ actualHypotenuse = 0,
+ actualOffsetHypotenuse = 0,
+ shortHeight = 0,
+ shortOffsetHeight = 0,
+ extraHeight = 0,
+ extraOffsetHeight = 0
+
//삼각형 도머
if (buttonAct === 3) {
- const bottomLength = height / (pitch * 0.25)
- const bottomOffsetLength = (height + offsetRef) / (pitch * 0.25)
+ let groupDormerPoints = [] //나중에 offset을 위한 포인트 저장용
addCanvasMouseEventListener('mouse:move', (e) => {
isDown = true
@@ -312,48 +337,51 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
}
})
- let angle = 0
- if (directionRef === 'left') {
- //서
- angle = 90
- } else if (directionRef === 'right') {
- //동
- angle = 270
- } else if (directionRef === 'up') {
- //북
- angle = 180
- }
+ if (selectedSurface) {
+ const roofAngle = selectedSurface.roofMaterial.angle
- dormer = new fabric.Triangle({
- fill: 'white',
- stroke: 'red',
- strokeDashArray: [5, 5],
- strokeWidth: 1,
- width: bottomLength * 2,
- height: height,
- left: pointer.x,
- top: pointer.y,
- selectable: true,
- lockMovementX: true,
- lockMovementY: true,
- lockRotation: true,
- lockScalingX: true,
- lockScalingY: true,
- name: dormerTempName,
- originX: 'center',
- originY: 'top',
- angle: angle,
- })
- canvas?.add(dormer)
+ theta = Math.atan(Math.tan((roofAngle * Math.PI) / 180) / Math.tan((dormerAngle * Math.PI) / 180))
- if (offsetRef > 0) {
- dormerOffset = new fabric.Triangle({
- fill: 'gray',
+ //센터 삼각형용
+ bottomLength = Number((Math.tan(theta) * height).toFixed())
+
+ //좌우 삼각형용
+ bottomOffsetLength = Number((Math.tan(theta) * (height + offsetRef)).toFixed())
+
+ planeHypotenuse = Math.sqrt(Math.pow(height, 2) + Math.pow(bottomLength, 2))
+
+ actualBottomLength = Math.sqrt(
+ Math.pow(Math.tan(theta) * height, 2) + Math.pow(Math.tan(theta) * height * Math.tan((dormerAngle * Math.PI) / 180), 2),
+ )
+ actualHypotenuse = Math.sqrt(Math.pow(height, 2) + Math.pow(actualBottomLength, 2))
+
+ actualBottomOffsetLength = Math.sqrt(
+ Math.pow(Math.tan(theta) * (height + offsetRef), 2) +
+ Math.pow(Math.tan(theta) * (height + offsetRef) * Math.tan((dormerAngle * Math.PI) / 180), 2),
+ )
+
+ planeOffsetHypotenuse = Math.sqrt(Math.pow(height + offsetRef, 2) + Math.pow(bottomOffsetLength, 2))
+ actualOffsetHypotenuse = Math.sqrt(Math.pow(height + offsetRef, 2) + Math.pow(actualBottomOffsetLength, 2))
+
+ let angle = 0
+ if (directionRef === 'left') {
+ //서
+ angle = 90
+ } else if (directionRef === 'right') {
+ //동
+ angle = 270
+ } else if (directionRef === 'up') {
+ //북
+ angle = 180
+ }
+
+ dormer = new fabric.Triangle({
+ fill: 'white',
stroke: 'red',
strokeDashArray: [5, 5],
strokeWidth: 1,
- width: bottomOffsetLength * 2,
- height: height + offsetRef,
+ width: bottomLength * 2,
+ height: height,
left: pointer.x,
top: pointer.y,
selectable: true,
@@ -366,15 +394,39 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
originX: 'center',
originY: 'top',
angle: angle,
- objectId: id,
})
- canvas?.add(dormerOffset)
+ canvas?.add(dormer)
+
+ if (offsetRef > 0) {
+ dormerOffset = new fabric.Triangle({
+ fill: 'gray',
+ stroke: 'red',
+ strokeDashArray: [5, 5],
+ strokeWidth: 1,
+ width: bottomOffsetLength * 2,
+ height: height + offsetRef,
+ left: pointer.x,
+ top: pointer.y,
+ selectable: true,
+ lockMovementX: true,
+ lockMovementY: true,
+ lockRotation: true,
+ lockScalingX: true,
+ lockScalingY: true,
+ name: dormerTempName,
+ originX: 'center',
+ originY: 'top',
+ angle: angle,
+ objectId: id,
+ })
+ canvas?.add(dormerOffset)
+ }
}
})
addCanvasMouseEventListener('mouse:up', (e) => {
if (dormer) {
- const trianglePolygon = pointsToTurfPolygon(triangleToPolygon(dormer))
+ const trianglePolygon = pointsToTurfPolygon(offsetRef > 0 ? getTrianglePoints(dormerOffset) : getTrianglePoints(dormer))
const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
//지붕 밖으로 그렸을때
@@ -403,9 +455,8 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
direction = 'north'
}
- const groupPoints = offsetRef > 0 ? triangleToPolygon(dormerOffset) : triangleToPolygon(dormer)
-
- let splitedTriangle = offsetRef > 0 ? splitDormerTriangle(dormerOffset, directionRef) : splitDormerTriangle(dormer, directionRef)
+ let { leftPoints, rightPoints, groupPoints, dormerPoints } =
+ offsetRef > 0 ? splitDormerTriangle(dormerOffset, directionRef, dormer) : splitDormerTriangle(dormer, directionRef)
canvas?.remove(offsetRef > 0 ? dormerOffset : dormer)
if (offsetRef > 0)
@@ -416,50 +467,116 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
strokeDashArray: [0],
}) //오프셋이 있을땐 같이 도머로 만든다
- const leftTriangle = new QPolygon(splitedTriangle[0], {
- fill: 'white',
- stroke: 'black',
- strokeWidth: 1,
- selectable: true,
- lockMovementX: true, // X 축 이동 잠금
- lockMovementY: true, // Y 축 이동 잠금
- lockRotation: true, // 회전 잠금
- viewLengthText: true,
- // direction: direction,
- originX: 'center',
- originY: 'center',
- name: dormerName,
- pitch: pitch,
- fontSize: lengthTextFont.fontSize.value,
- fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
- fontWeight: lengthTextFont.fontWeight.value,
- })
+ const leftTriangle = addPolygon(
+ leftPoints,
+ {
+ fill: 'white',
+ stroke: 'black',
+ strokeWidth: 1,
+ selectable: true,
+ lockMovementX: true, // X 축 이동 잠금
+ lockMovementY: true, // Y 축 이동 잠금
+ lockRotation: true, // 회전 잠금
+ viewLengthText: true,
+ // direction: direction,
+ originX: 'center',
+ originY: 'center',
+ name: dormerName,
+ pitch: pitch,
+ fontSize: lengthTextFont.fontSize.value,
+ fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
+ fontWeight: lengthTextFont.fontWeight.value,
+ groupPoints: groupPoints,
+ dormerAttributes: {
+ height: height,
+ width: width,
+ pitch: pitch,
+ offsetRef: offsetRef,
+ offsetWidthRef: offsetWidthRef,
+ directionRef: directionRef,
+ },
+ lines: [
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(planeOffsetHypotenuse, 1) * 10,
+ actualSize: toFixedWithoutRounding(actualOffsetHypotenuse, 1) * 10,
+ },
+ },
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(bottomOffsetLength, 1) * 10,
+ actualSize: toFixedWithoutRounding(actualBottomOffsetLength, 1) * 10,
+ },
+ },
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(height + offsetRef, 1) * 10,
+ actualSize: toFixedWithoutRounding(height + offsetRef, 1) * 10,
+ },
+ },
+ ],
+ },
+ false,
+ )
- const rightTriangle = new QPolygon(splitedTriangle[1], {
- fill: 'white',
- stroke: 'black',
- strokeWidth: 1,
- selectable: true,
- lockMovementX: true, // X 축 이동 잠금
- lockMovementY: true, // Y 축 이동 잠금
- lockRotation: true, // 회전 잠금
- viewLengthText: true,
- // direction: direction,
- originX: 'center',
- originY: 'center',
- name: dormerName,
- pitch: pitch,
- fontSize: lengthTextFont.fontSize.value,
- fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
- fontWeight: lengthTextFont.fontWeight.value,
- })
+ const rightTriangle = addPolygon(
+ rightPoints,
+ {
+ fill: 'white',
+ stroke: 'black',
+ strokeWidth: 1,
+ selectable: true,
+ lockMovementX: true, // X 축 이동 잠금
+ lockMovementY: true, // Y 축 이동 잠금
+ lockRotation: true, // 회전 잠금
+ viewLengthText: true,
+ // direction: direction,
+ originX: 'center',
+ originY: 'center',
+ name: dormerName,
+ pitch: pitch,
+ fontSize: lengthTextFont.fontSize.value,
+ fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
+ fontWeight: lengthTextFont.fontWeight.value,
+ groupPoints: groupPoints,
+ dormerAttributes: {
+ height: height,
+ width: width,
+ pitch: pitch,
+ offsetRef: offsetRef,
+ offsetWidthRef: offsetWidthRef,
+ directionRef: directionRef,
+ },
+ lines: [
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(height + offsetRef, 1) * 10,
+ actualSize: toFixedWithoutRounding(height + offsetRef, 1) * 10,
+ },
+ },
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(bottomOffsetLength, 1) * 10,
+ actualSize: toFixedWithoutRounding(actualBottomOffsetLength, 1) * 10,
+ },
+ },
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(planeOffsetHypotenuse, 1) * 10,
+ actualSize: toFixedWithoutRounding(actualOffsetHypotenuse, 1) * 10,
+ },
+ },
+ ],
+ },
+ false,
+ )
// canvas?.add(leftTriangle)
// canvas?.add(rightTriangle)
//패턴
- setSurfaceShapePattern(leftTriangle)
- setSurfaceShapePattern(rightTriangle)
+ setSurfaceShapePattern(leftTriangle, roofDisplay.column, false, selectedSurface.roofMaterial, true)
+ setSurfaceShapePattern(rightTriangle, roofDisplay.column, false, selectedSurface.roofMaterial, true)
//방향
// drawDirectionArrow(leftTriangle)
@@ -467,28 +584,68 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
let offsetPolygon
+ groupDormerPoints = groupPoints
+
if (offsetRef > 0) {
canvas?.remove(dormer)
- offsetPolygon = new QPolygon(triangleToPolygon(dormer), {
- selectable: true,
- lockMovementX: true, // X 축 이동 잠금
- lockMovementY: true, // Y 축 이동 잠금
- lockRotation: true, // 회전 잠금
- viewLengthText: true,
- name: 'triangleDormerOffset',
- id: id,
- fill: 'rgba(255, 255, 255, 0.6)',
- stroke: 'black',
- strokeWidth: 1,
- originX: 'center',
- originY: 'center',
- fontSize: lengthTextFont.fontSize.value,
- fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
- fontWeight: lengthTextFont.fontWeight.value,
- })
+ offsetPolygon = addPolygon(
+ dormerPoints,
+ {
+ selectable: true,
+ lockMovementX: true, // X 축 이동 잠금
+ lockMovementY: true, // Y 축 이동 잠금
+ lockRotation: true, // 회전 잠금
+ viewLengthText: true,
+ name: 'triangleDormerOffset',
+ id: id,
+ fill: 'rgba(255, 255, 255, 0.6)',
+ stroke: 'black',
+ strokeWidth: 1,
+ originX: 'center',
+ originY: 'top',
+ fontSize: lengthTextFont.fontSize.value,
+ fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
+ fontWeight: lengthTextFont.fontWeight.value,
+ // angle: originAngle,
+ pitch: pitch,
+ dormerAttributes: {
+ height: height,
+ width: width,
+ pitch: pitch,
+ offsetRef: offsetRef,
+ offsetWidthRef: offsetWidthRef,
+ directionRef: directionRef,
+ },
+ lines: [
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(planeHypotenuse, 1) * 10,
+ actualSize: toFixedWithoutRounding(actualHypotenuse, 1) * 10,
+ },
+ },
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(bottomLength * 2, 1) * 10,
+ actualSize: toFixedWithoutRounding(bottomLength * 2, 1) * 10,
+ },
+ },
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(planeHypotenuse, 1) * 10,
+ actualSize: toFixedWithoutRounding(actualHypotenuse, 1) * 10,
+ },
+ },
+ ],
+ },
+ false,
+ )
}
+ // addLengthText(leftTriangle)
+ // addLengthText(rightTriangle)
+ // if (offsetRef > 0) addLengthText(offsetPolygon)
+
const groupPolygon = offsetPolygon ? [leftTriangle, rightTriangle, offsetPolygon] : [leftTriangle, rightTriangle]
const objectGroup = new fabric.Group(groupPolygon, {
@@ -498,14 +655,10 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
parentId: selectedSurface.id,
originX: 'center',
originY: 'center',
- groupPoints: groupPoints,
+ groupPoints: groupDormerPoints,
})
canvas?.add(objectGroup)
- objectGroup.getObjects().forEach((obj, index) => {
- console.log(`최초 pathOffset ${index}`, obj.get('pathOffset'))
- })
-
objectGroup._objects.forEach((obj) => {
if (obj.hasOwnProperty('texts')) {
obj.texts.forEach((text) => {
@@ -516,15 +669,11 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
isDown = false
initEvent()
- dbClickEvent()
+ // dbClickEvent()
if (setIsHidden) setIsHidden(false)
}
})
} else if (buttonAct === 4) {
- const heightLength = height - (width / 2) * (pitch * 0.25)
- //(동의길이 깊이)+출폭(깊이)-[(입력한 폭값)/2+출폭(폭)]*(0.25*입력한 寸)
- const heightOffsetLength = height + offsetRef - (width / 2 + offsetWidthRef) * (pitch * 0.25)
-
addCanvasMouseEventListener('mouse:move', (e) => {
isDown = true
if (!isDown) return
@@ -538,55 +687,57 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
}
})
- let angle = 0
- if (directionRef === 'left') {
- //서
- angle = 90
- } else if (directionRef === 'right') {
- //동
- angle = 270
- } else if (directionRef === 'up') {
- //북
- angle = 180
- }
+ if (selectedSurface) {
+ const roofAngle = selectedSurface.roofMaterial.angle
- pentagonPoints = [
- { x: pointer.x, y: pointer.y },
- { x: pointer.x - width / 2, y: pointer.y + (height - heightLength) },
- { x: pointer.x - width / 2, y: pointer.y + height },
- { x: pointer.x + width / 2, y: pointer.y + height },
- { x: pointer.x + width / 2, y: pointer.y + (height - heightLength) },
- ]
+ theta = Math.atan(Math.tan((roofAngle * Math.PI) / 180) / Math.tan((dormerAngle * Math.PI) / 180))
- pentagonOffsetPoints = [
- { x: pointer.x, y: pointer.y },
- { x: pointer.x - width / 2 - offsetWidthRef, y: pointer.y + height + offsetRef - heightOffsetLength },
- { x: pointer.x - width / 2 - offsetWidthRef, y: pointer.y + height + offsetRef },
- { x: pointer.x + width / 2 + offsetWidthRef, y: pointer.y + height + offsetRef },
- { x: pointer.x + width / 2 + offsetWidthRef, y: pointer.y + height + offsetRef - heightOffsetLength },
- ]
+ //5각형중에 3각형의 높이 작은영역
+ shortHeight = width / 2 / Math.tan(theta)
+ extraHeight = height - shortHeight
+ planeHypotenuse = Math.sqrt(Math.pow(shortHeight, 2) + Math.pow(width / 2, 2))
+ actualBottomLength = Math.sqrt(Math.pow((width / 2) * Math.tan((dormerAngle * Math.PI) / 180), 2) + Math.pow(width / 2, 2))
+ actualHypotenuse = Math.sqrt(Math.pow(actualBottomLength, 2) + Math.pow(shortHeight, 2))
- dormer = new QPolygon(pentagonPoints, {
- fill: 'white',
- stroke: 'red',
- strokeDashArray: [5, 5],
- strokeWidth: 1,
- selectable: true,
- lockMovementX: true,
- lockMovementY: true,
- lockRotation: true,
- lockScalingX: true,
- lockScalingY: true,
- name: dormerTempName,
- originX: 'center',
- originY: 'top',
- angle: angle,
- })
- canvas?.add(dormer)
+ //큰영역
+ shortOffsetHeight = (width / 2 + offsetWidthRef) / Math.tan(theta)
+ extraOffsetHeight = height + offsetRef - shortOffsetHeight
+ planeOffsetHypotenuse = Math.sqrt(Math.pow(shortOffsetHeight, 2) + Math.pow(width / 2 + offsetWidthRef, 2))
+ actualBottomOffsetLength = Math.sqrt(
+ Math.pow((width / 2 + offsetWidthRef) * Math.tan((dormerAngle * Math.PI) / 180), 2) + Math.pow(width / 2 + +offsetWidthRef, 2),
+ )
+ actualOffsetHypotenuse = Math.sqrt(Math.pow(actualBottomOffsetLength, 2) + Math.pow(shortOffsetHeight, 2))
- if (offsetRef > 0 || offsetWidthRef > 0) {
- dormerOffset = new QPolygon(pentagonOffsetPoints, {
- fill: 'gray',
+ let angle = 0
+ if (directionRef === 'left') {
+ //서
+ angle = 90
+ } else if (directionRef === 'right') {
+ //동
+ angle = 270
+ } else if (directionRef === 'up') {
+ //북
+ angle = 180
+ }
+
+ pentagonPoints = [
+ { x: pointer.x, y: pointer.y },
+ { x: pointer.x - width / 2, y: pointer.y + (height - extraHeight) },
+ { x: pointer.x - width / 2, y: pointer.y + height },
+ { x: pointer.x + width / 2, y: pointer.y + height },
+ { x: pointer.x + width / 2, y: pointer.y + (height - extraHeight) },
+ ]
+
+ pentagonOffsetPoints = [
+ { x: pointer.x, y: pointer.y },
+ { x: pointer.x - width / 2 - offsetWidthRef, y: pointer.y + height + offsetRef - extraOffsetHeight },
+ { x: pointer.x - width / 2 - offsetWidthRef, y: pointer.y + height + offsetRef },
+ { x: pointer.x + width / 2 + offsetWidthRef, y: pointer.y + height + offsetRef },
+ { x: pointer.x + width / 2 + offsetWidthRef, y: pointer.y + height + offsetRef - extraOffsetHeight },
+ ]
+
+ dormer = new QPolygon(pentagonPoints, {
+ fill: 'white',
stroke: 'red',
strokeDashArray: [5, 5],
strokeWidth: 1,
@@ -601,13 +752,33 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
originY: 'top',
angle: angle,
})
- canvas?.add(dormerOffset)
+ canvas?.add(dormer)
+
+ if (offsetRef > 0 || offsetWidthRef > 0) {
+ dormerOffset = new QPolygon(pentagonOffsetPoints, {
+ fill: 'gray',
+ stroke: 'red',
+ strokeDashArray: [5, 5],
+ strokeWidth: 1,
+ selectable: true,
+ lockMovementX: true,
+ lockMovementY: true,
+ lockRotation: true,
+ lockScalingX: true,
+ lockScalingY: true,
+ name: dormerTempName,
+ originX: 'center',
+ originY: 'top',
+ angle: angle,
+ })
+ canvas?.add(dormerOffset)
+ }
}
})
addCanvasMouseEventListener('mouse:up', (e) => {
if (dormer) {
- const pentagonPolygon = pointsToTurfPolygon(dormer.points)
+ const pentagonPolygon = pointsToTurfPolygon(offsetRef > 0 ? dormerOffset.getCurrentPoints() : dormer.getCurrentPoints())
const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
//지붕 밖으로 그렸을때
@@ -620,23 +791,25 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
//각도 추가
+ let originAngle = 0 //기본 남쪽
let direction = 'south'
+
if (directionRef === 'left') {
//서
+ originAngle = 90
direction = 'west'
} else if (directionRef === 'right') {
//동
+ originAngle = 270
direction = 'east'
} else if (directionRef === 'up') {
//북
+ originAngle = 180
direction = 'north'
}
- const offsetMode = offsetRef > 0 || offsetWidthRef > 0 ? 'offset' : 'normal'
- let splitedPentagon =
- offsetRef > 0 || offsetWidthRef > 0
- ? splitDormerPentagon(dormerOffset, directionRef, offsetMode)
- : splitDormerPentagon(dormer, directionRef, offsetMode)
+ let { leftPoints, rightPoints, groupPoints } =
+ offsetRef > 0 || offsetWidthRef > 0 ? splitDormerPentagon(dormerOffset, directionRef) : splitDormerPentagon(dormer, directionRef)
canvas?.remove(offsetRef > 0 || offsetWidthRef > 0 ? dormerOffset : dormer)
if (offsetRef > 0)
@@ -647,46 +820,126 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
strokeDashArray: [0],
}) //오프셋이 있을땐 같이 도머로 만든다
- const leftPentagon = new QPolygon(splitedPentagon[0], {
- fill: 'transparent',
- stroke: 'red',
- strokeWidth: 1,
- selectable: true,
- lockMovementX: true, // X 축 이동 잠금
- lockMovementY: true, // Y 축 이동 잠금
- lockRotation: true, // 회전 잠금
- viewLengthText: true,
- fontSize: 14,
- // direction: direction,
- originX: 'center',
- originY: 'center',
- name: dormerName,
- pitch: pitch,
- })
+ const leftPentagon = addPolygon(
+ leftPoints,
+ {
+ fill: 'transparent',
+ stroke: 'red',
+ strokeWidth: 1,
+ selectable: true,
+ lockMovementX: true, // X 축 이동 잠금
+ lockMovementY: true, // Y 축 이동 잠금
+ lockRotation: true, // 회전 잠금
+ viewLengthText: true,
+ fontSize: 14,
+ // direction: direction,
+ originX: 'center',
+ originY: 'center',
+ name: dormerName,
+ pitch: pitch,
+ groupPoints: groupPoints,
+ dormerAttributes: {
+ height: height,
+ width: width,
+ pitch: pitch,
+ offsetRef: offsetRef,
+ offsetWidthRef: offsetWidthRef,
+ directionRef: directionRef,
+ },
+ lines: [
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(planeOffsetHypotenuse, 1) * 10,
+ actualSize: toFixedWithoutRounding(actualOffsetHypotenuse, 1) * 10,
+ },
+ },
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(extraOffsetHeight, 1) * 10,
+ actualSize: toFixedWithoutRounding(extraOffsetHeight, 1) * 10,
+ },
+ },
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(width / 2 + offsetWidthRef, 1) * 10,
+ actualSize: toFixedWithoutRounding(actualBottomOffsetLength, 1) * 10,
+ },
+ },
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(height + offsetRef, 1) * 10,
+ actualSize: toFixedWithoutRounding(height + offsetRef, 1) * 10,
+ },
+ },
+ ],
+ },
+ false,
+ )
- const rightPentagon = new QPolygon(splitedPentagon[1], {
- fill: 'transparent',
- stroke: 'red',
- strokeWidth: 1,
- selectable: true,
- lockMovementX: true, // X 축 이동 잠금
- lockMovementY: true, // Y 축 이동 잠금
- lockRotation: true, // 회전 잠금
- viewLengthText: true,
- fontSize: 14,
- // direction: direction,
- originX: 'center',
- originY: 'center',
- name: dormerName,
- pitch: pitch,
- })
+ const rightPentagon = addPolygon(
+ rightPoints,
+ {
+ fill: 'transparent',
+ stroke: 'red',
+ strokeWidth: 1,
+ selectable: true,
+ lockMovementX: true, // X 축 이동 잠금
+ lockMovementY: true, // Y 축 이동 잠금
+ lockRotation: true, // 회전 잠금
+ viewLengthText: true,
+ fontSize: 14,
+ // direction: direction,
+ originX: 'center',
+ originY: 'center',
+ name: dormerName,
+ pitch: pitch,
+ groupPoints: groupPoints,
+ dormerAttributes: {
+ height: height,
+ width: width,
+ pitch: pitch,
+ offsetRef: offsetRef,
+ offsetWidthRef: offsetWidthRef,
+ directionRef: directionRef,
+ },
+ lines: [
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(height + offsetRef, 1) * 10,
+ actualSize: toFixedWithoutRounding(height + offsetRef, 1) * 10,
+ },
+ },
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(width / 2 + offsetWidthRef, 1) * 10,
+ actualSize: toFixedWithoutRounding(actualBottomOffsetLength, 1) * 10,
+ },
+ },
+
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(extraOffsetHeight, 1) * 10,
+ actualSize: toFixedWithoutRounding(extraOffsetHeight, 1) * 10,
+ },
+ },
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(planeOffsetHypotenuse, 1) * 10,
+ actualSize: toFixedWithoutRounding(actualOffsetHypotenuse, 1) * 10,
+ },
+ },
+ ],
+ },
+ false,
+ )
// canvas?.add(leftPentagon)
// canvas?.add(rightPentagon)
//패턴
- setSurfaceShapePattern(leftPentagon)
- setSurfaceShapePattern(rightPentagon)
+
+ setSurfaceShapePattern(leftPentagon, roofDisplay.column, false, selectedSurface.roofMaterial, true)
+ setSurfaceShapePattern(rightPentagon, roofDisplay.column, false, selectedSurface.roofMaterial, true)
//방향
// drawDirectionArrow(leftPentagon)
// drawDirectionArrow(rightPentagon)
@@ -696,27 +949,76 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
if (offsetRef > 0) {
canvas?.remove(dormer)
- offsetPolygon = new QPolygon(dormer.points, {
- selectable: true,
- lockMovementX: true, // X 축 이동 잠금
- lockMovementY: true, // Y 축 이동 잠금
- lockRotation: true, // 회전 잠금
- viewLengthText: true,
- name: 'pentagonDormerOffset',
- id: id,
- fill: 'rgba(255, 255, 255, 0.6)',
- stroke: 'black',
- strokeWidth: 1,
- originX: 'center',
- originY: 'center',
- fontSize: lengthTextFont.fontSize.value,
- fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
- fontWeight: lengthTextFont.fontWeight.value,
- })
+ offsetPolygon = addPolygon(
+ dormer.getCurrentPoints(),
+ {
+ selectable: true,
+ lockMovementX: true, // X 축 이동 잠금
+ lockMovementY: true, // Y 축 이동 잠금
+ lockRotation: true, // 회전 잠금
+ viewLengthText: true,
+ name: 'pentagonDormerOffset',
+ id: id,
+ fill: 'rgba(255, 255, 255, 0.6)',
+ stroke: 'black',
+ strokeWidth: 1,
+ originX: 'center',
+ originY: 'top',
+ fontSize: lengthTextFont.fontSize.value,
+ fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
+ fontWeight: lengthTextFont.fontWeight.value,
+ // angle: originAngle,
+ groupPoints: groupPoints,
+ dormerAttributes: {
+ height: height,
+ width: width,
+ pitch: pitch,
+ offsetRef: offsetRef,
+ offsetWidthRef: offsetWidthRef,
+ directionRef: directionRef,
+ },
+ lines: [
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(planeHypotenuse, 1) * 10,
+ actualSize: toFixedWithoutRounding(actualHypotenuse, 1) * 10,
+ },
+ },
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(extraHeight, 1) * 10,
+ actualSize: toFixedWithoutRounding(extraHeight, 1) * 10,
+ },
+ },
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(width, 1) * 10,
+ actualSize: toFixedWithoutRounding(actualBottomLength * 2, 1) * 10,
+ },
+ },
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(extraHeight, 1) * 10,
+ actualSize: toFixedWithoutRounding(extraHeight, 1) * 10,
+ },
+ },
+ {
+ attributes: {
+ planeSize: toFixedWithoutRounding(planeHypotenuse, 1) * 10,
+ actualSize: toFixedWithoutRounding(actualHypotenuse, 1) * 10,
+ },
+ },
+ ],
+ },
+ false,
+ )
}
+ // addLengthText(leftPentagon)
+ // addLengthText(rightPentagon)
+ // addLengthText(offsetPolygon)
+
const groupPolygon = offsetPolygon ? [leftPentagon, rightPentagon, offsetPolygon] : [leftPentagon, rightPentagon]
- const groupPoints = offsetRef > 0 ? pentagonOffsetPoints : pentagonPoints
const objectGroup = new fabric.Group(groupPolygon, {
subTargetCheck: true,
@@ -741,7 +1043,8 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
isDown = false
initEvent()
- dbClickEvent()
+ // dbClickEvent()
+ if (setIsHidden) setIsHidden(false)
}
})
}
@@ -762,11 +1065,17 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
if (setIsHidden) setIsHidden(false)
}
- const splitDormerTriangle = (triangle, direction) => {
+ const splitDormerTriangle = (triangle, direction, dormer = null) => {
const halfWidth = triangle.width / 2
+ let dormerPoints = []
let leftPoints = []
let rightPoints = []
+ let groupPoints = []
+
+ if (dormer) {
+ dormerPoints = getTrianglePoints(dormer)
+ }
if (direction === 'down') {
leftPoints = [
@@ -780,6 +1089,12 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
{ x: triangle.left, y: triangle.top + triangle.height },
{ x: triangle.left + halfWidth, y: triangle.top + triangle.height },
]
+
+ groupPoints = [
+ { x: triangle.left, y: triangle.top },
+ { x: triangle.left - halfWidth, y: triangle.top + triangle.height },
+ { x: triangle.left + halfWidth, y: triangle.top + triangle.height },
+ ]
} else if (direction === 'up') {
leftPoints = [
{ x: triangle.left, y: triangle.top },
@@ -792,6 +1107,12 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
{ x: triangle.left, y: triangle.top - triangle.height },
{ x: triangle.left + halfWidth, y: triangle.top - triangle.height },
]
+
+ groupPoints = [
+ { x: triangle.left, y: triangle.top },
+ { x: triangle.left - halfWidth, y: triangle.top - triangle.height },
+ { x: triangle.left + halfWidth, y: triangle.top - triangle.height },
+ ]
} else if (direction === 'left') {
leftPoints = [
{ x: triangle.left, y: triangle.top },
@@ -804,20 +1125,32 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
{ x: triangle.left - triangle.height, y: triangle.top },
{ x: triangle.left - triangle.height, y: triangle.top + halfWidth },
]
+
+ groupPoints = [
+ { x: triangle.left, y: triangle.top },
+ { x: triangle.left - triangle.height, y: triangle.top - halfWidth },
+ { x: triangle.left - triangle.height, y: triangle.top + halfWidth },
+ ]
} else if (direction === 'right') {
leftPoints = [
{ x: triangle.left, y: triangle.top },
+ { x: triangle.left + triangle.height, y: triangle.top + halfWidth },
{ x: triangle.left + triangle.height, y: triangle.top },
- { x: triangle.left + triangle.height, y: triangle.top + triangle.height },
]
rightPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top },
- { x: triangle.left + triangle.height, y: triangle.top - triangle.height },
+ { x: triangle.left + triangle.height, y: triangle.top - halfWidth },
+ ]
+
+ groupPoints = [
+ { x: triangle.left, y: triangle.top },
+ { x: triangle.left + triangle.height, y: triangle.top + halfWidth },
+ { x: triangle.left + triangle.height, y: triangle.top - halfWidth },
]
}
- return [leftPoints, rightPoints]
+ return { leftPoints, rightPoints, groupPoints, dormerPoints }
}
const splitDormerPentagon = (pentagon, direction, offsetMode) => {
@@ -825,6 +1158,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
let leftPoints = []
let rightPoints = []
+ let groupPoints = []
if (direction === 'down') {
leftPoints = [
@@ -840,6 +1174,14 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
{ x: points[3].x, y: points[3].y },
{ x: points[4].x, y: points[4].y },
]
+
+ groupPoints = [
+ { x: points[0].x, y: points[0].y },
+ { x: points[1].x, y: points[1].y },
+ { x: points[2].x, y: points[3].y },
+ { x: points[3].x, y: points[3].y },
+ { x: points[4].x, y: points[4].y },
+ ]
} else if (direction === 'up') {
leftPoints = [
{ x: points[0].x, y: points[0].y },
@@ -850,9 +1192,17 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
rightPoints = [
{ x: points[0].x, y: points[0].y },
- { x: points[3].x, y: points[0].y - (points[1].y - points[0].y) },
- { x: points[3].x, y: points[0].y - (points[2].y - points[0].y) },
{ x: points[0].x, y: points[0].y - (points[2].y - points[0].y) },
+ { x: points[3].x, y: points[0].y - (points[2].y - points[0].y) },
+ { x: points[3].x, y: points[0].y - (points[1].y - points[0].y) },
+ ]
+
+ groupPoints = [
+ { x: points[0].x, y: points[0].y }, // 기준점
+ { x: points[1].x, y: points[0].y - (points[1].y - points[0].y) },
+ { x: points[2].x, y: points[0].y - (points[2].y - points[0].y) },
+ { x: points[3].x, y: points[0].y - (points[2].y - points[0].y) },
+ { x: points[3].x, y: points[0].y - (points[1].y - points[0].y) },
]
} else if (direction === 'left') {
leftPoints = [
@@ -867,12 +1217,26 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
rightPoints = [
{ x: points[0].x, y: points[0].y },
- { x: points[0].x - (points[1].y - points[0].y), y: points[0].y + (points[0].x - points[1].x) },
+ { x: points[0].x - (points[1].y - points[0].y) - (points[2].y - points[1].y), y: points[0].y },
{
x: points[0].x - (points[1].y - points[0].y) - (points[2].y - points[1].y),
y: points[0].y + (points[0].x - points[1].x),
},
- { x: points[0].x - (points[1].y - points[0].y) - (points[2].y - points[1].y), y: points[0].y },
+ { x: points[0].x - (points[1].y - points[0].y), y: points[0].y + (points[0].x - points[1].x) },
+ ]
+
+ groupPoints = [
+ { x: points[0].x, y: points[0].y },
+ { x: points[0].x - (points[1].y - points[0].y), y: points[0].y - (points[0].x - points[1].x) },
+ {
+ x: points[0].x - (points[1].y - points[0].y) - (points[2].y - points[1].y),
+ y: points[0].y - (points[0].x - points[1].x),
+ },
+ {
+ x: points[0].x - (points[1].y - points[0].y) - (points[2].y - points[1].y),
+ y: points[0].y + (points[0].x - points[1].x),
+ },
+ { x: points[0].x - (points[1].y - points[0].y), y: points[0].y + (points[0].x - points[1].x) },
]
} else if (direction === 'right') {
leftPoints = [
@@ -887,23 +1251,39 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
rightPoints = [
{ x: points[0].x, y: points[0].y },
- { x: points[0].x + (points[1].y - points[0].y), y: points[0].y - (points[0].x - points[1].x) },
+ { x: points[0].x + (points[1].y - points[0].y) + (points[2].y - points[1].y), y: points[0].y },
{
x: points[0].x + (points[1].y - points[0].y) + (points[2].y - points[1].y),
y: points[0].y - (points[0].x - points[1].x),
},
- { x: points[0].x + (points[1].y - points[0].y) + (points[2].y - points[1].y), y: points[0].y },
+ { x: points[0].x + (points[1].y - points[0].y), y: points[0].y - (points[0].x - points[1].x) },
+ ]
+
+ groupPoints = [
+ { x: points[0].x, y: points[0].y },
+ { x: points[0].x + (points[1].y - points[0].y), y: points[0].y + (points[0].x - points[1].x) },
+ {
+ x: points[0].x + (points[1].y - points[0].y) + (points[2].y - points[1].y),
+ y: points[0].y + (points[0].x - points[1].x),
+ },
+ {
+ x: points[0].x + (points[1].y - points[0].y) + (points[2].y - points[1].y),
+ y: points[0].y - (points[0].x - points[1].x),
+ },
+ { x: points[0].x + (points[1].y - points[0].y), y: points[0].y - (points[0].x - points[1].x) },
]
}
- return [leftPoints, rightPoints]
+ return { leftPoints, rightPoints, groupPoints }
}
- const resizeObjectBatch = (side, target, width, height) => {
+ const resizeObjectBatch = (side, target, width, height, popupId) => {
const objectWidth = target.width
const objectHeight = target.height
- const changeWidth = (width / 10 / objectWidth).toFixed(2)
- const changeHeight = (height / 10 / objectHeight).toFixed(2)
+
+ const changeWidth = toFixedWithoutRounding(width / 10 / objectWidth, 1)
+ const changeHeight = toFixedWithoutRounding(height / 10 / objectHeight, 1)
+
let sideX = 'left'
let sideY = 'top'
@@ -935,40 +1315,52 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
target.scaleX = changeWidth || 1
target.scaleY = changeHeight || 1
+ canvas?.renderAll() //변경 좌표를 한번 적용
+
//크기 변경후 좌표를 재 적용
- const changedCoords = target.getPointByOrigin('center', 'center')
+ const changedCoords = target.getPointByOrigin(target.originX, target.originY)
target.set({
...target,
- originX: 'center',
- originY: 'center',
+ originX: target.originX,
+ originY: target.originY,
left: changedCoords.x,
top: changedCoords.y,
- width: width / 10,
- height: height / 10,
+ height: toFixedWithoutRounding(height / 10, 1),
+ width: toFixedWithoutRounding(width / 10, 1),
+ scaleX: 1,
+ scaleY: 1,
})
- //얘는 일단 도머에 적용함
- if (target.type === 'group') {
- target._objects.forEach((obj) => setSurfaceShapePattern(obj))
- }
-
// target.setCoords()
canvas.renderAll()
+
+ const currentPoints = rectToPolygon(target)
+ target.points = currentPoints
+
if (target.type === 'group') reGroupObject(target)
+
+ closePopup(popupId)
}
const reGroupObject = (groupObj) => {
groupObj._restoreObjectsState() //이건 실행만 되도 그룹이 변경됨
+
const reGroupObjects = []
groupObj._objects.forEach((obj) => {
- const newObj = new QPolygon(obj.getCurrentPoints(), {
- ...obj,
- points: obj.getCurrentPoints(),
- scaleX: 1,
- scaleY: 1,
- texts: [],
- })
+ const newObj = addPolygon(
+ obj.getCurrentPoints(),
+ {
+ ...obj,
+ points: obj.getCurrentPoints(),
+ scaleX: 1,
+ scaleY: 1,
+ lines: obj.lines ?? [],
+ groupPoints: groupObj.groupPoints ?? [],
+ groupId: groupObj.groupId ?? '',
+ },
+ false,
+ )
reGroupObjects.push(newObj)
canvas.remove(obj)
if (newObj.direction) {
@@ -976,6 +1368,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
}
newObj.fire('modified')
})
+
const reGroup = new fabric.Group(reGroupObjects, {
subTargetCheck: true,
name: groupObj.name,
@@ -984,10 +1377,20 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
parentId: groupObj.parentId,
originX: 'center',
originY: 'center',
+ groupPoints: groupObj.groupPoints ?? [],
+ groupId: groupObj.groupId ?? '',
})
canvas?.add(reGroup)
canvas?.remove(groupObj)
+ reGroup._objects.forEach((obj) => {
+ if (obj.hasOwnProperty('texts')) {
+ obj.texts.forEach((text) => {
+ text.bringToFront()
+ })
+ }
+ })
+
return reGroup
}
@@ -1002,6 +1405,10 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
})
const originObj = { ...obj }
+ const turfSurface = pointsToTurfPolygon(parentSurface.getCurrentPoints())
+ const originLeft = obj.left
+ const originTop = obj.top
+
addCanvasMouseEventListener('mouse:up', (e) => {
//개구, 그림자 타입일 경우 폴리곤 타입 변경
if (BATCH_TYPE.OPENING === obj.name || BATCH_TYPE.SHADOW === obj.name) {
@@ -1009,22 +1416,30 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
points: rectToPolygon(obj),
})
- const turfSurface = pointsToTurfPolygon(parentSurface.points)
- const turfObject = pointsToTurfPolygon(obj.points)
+ //그림자는 아무데나 설치 할 수 있게 해달라고 함
+ if (obj.name === BATCH_TYPE.OPENING) {
+ const turfObject = pointsToTurfPolygon(obj.points)
- if (turf.booleanWithin(turfObject, turfSurface)) {
+ if (turf.booleanWithin(turfObject, turfSurface)) {
+ obj.set({
+ lockMovementX: true,
+ lockMovementY: true,
+ })
+
+ obj.setCoords()
+ } else {
+ swalFire({
+ title: getMessage('batch.object.outside.roof'),
+ icon: 'warning',
+ })
+ obj.set({ ...originObj, lockMovementX: true, lockMovementY: true })
+ }
+ } else {
obj.set({
lockMovementX: true,
lockMovementY: true,
})
-
- obj.setCoords()
- } else {
- swalFire({
- title: getMessage('batch.object.outside.roof'),
- icon: 'warning',
- })
- obj.set({ ...originObj, lockMovementX: true, lockMovementY: true })
+ obj.bringToFront()
}
} else {
obj.set({
@@ -1032,8 +1447,36 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
lockMovementY: true,
})
- if (obj.type === 'group') reGroupObject(obj)
- obj.setCoords()
+ if (obj.name === BATCH_TYPE.TRIANGLE_DORMER || obj.name === BATCH_TYPE.PENTAGON_DORMER) {
+ const calcLeft = obj.left - originLeft
+ const calcTop = obj.top - originTop
+
+ const currentDormerPoints = obj.groupPoints.map((item) => {
+ return {
+ x: item.x + calcLeft,
+ y: item.y + calcTop,
+ }
+ })
+
+ const turfObject = pointsToTurfPolygon(currentDormerPoints)
+
+ if (turf.booleanWithin(turfObject, turfSurface)) {
+ obj.set({
+ lockMovementX: true,
+ lockMovementY: true,
+ groupPoints: currentDormerPoints,
+ })
+
+ if (obj.type === 'group') reGroupObject(obj)
+ obj.setCoords()
+ } else {
+ swalFire({
+ title: getMessage('batch.object.outside.roof'),
+ icon: 'warning',
+ })
+ obj.set({ ...originObj, lockMovementX: true, lockMovementY: true })
+ }
+ }
}
canvas.discardActiveObject()
initEvent()
@@ -1126,12 +1569,69 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
length2 = parseInt(length2) / 10
const dormer = canvas.getActiveObject()
- if (length1) dormer.top = arrow1 === 'down' ? dormer.top + length1 : dormer.top - length1
- if (length2) dormer.left = arrow2 === 'left' ? dormer.left - length2 : dormer.left + length2
+ const { left, top } = dormer
+
+ if (length1) {
+ if (!arrow1) {
+ swalFire({
+ title: getMessage('length.direction.is.required'),
+ icon: 'warning',
+ })
+ } else {
+ dormer.top = arrow1 === 'down' ? dormer.top + length1 : dormer.top - length1
+ }
+ }
+
+ if (length2) {
+ if (!arrow2) {
+ swalFire({
+ title: getMessage('length.direction.is.required'),
+ icon: 'warning',
+ })
+ } else {
+ dormer.left = arrow2 === 'left' ? dormer.left - length2 : dormer.left + length2
+ }
+ }
+
+ const parentSurface = canvas?.getObjects().filter((item) => item.name === POLYGON_TYPE.ROOF && item.id === dormer.parentId)[0]
+ const turfSurface = pointsToTurfPolygon(parentSurface.getCurrentPoints())
+
+ let turfDormer = pointsToTurfPolygon(rectToPolygon(dormer))
+ let currentPoints = []
+ if (dormer.name === BATCH_TYPE.TRIANGLE_DORMER || dormer.name === BATCH_TYPE.PENTAGON_DORMER) {
+ const calcLeft = dormer.left - left
+ const calcTop = dormer.top - top
+
+ currentPoints = dormer.groupPoints.map((item) => {
+ return {
+ x: item.x + calcLeft,
+ y: item.y + calcTop,
+ }
+ })
+
+ turfDormer = pointsToTurfPolygon(currentPoints)
+ }
+
+ if (!turf.booleanWithin(turfDormer, turfSurface)) {
+ swalFire({
+ title: getMessage('batch.object.outside.roof'),
+ icon: 'warning',
+ })
+
+ //위치 원복`
+ dormer.left = left
+ dormer.top = top
+
+ return
+ }
if (dormer.type === 'group') {
+ dormer.set({ groupPoints: currentPoints })
const newDormer = reGroupObject(dormer)
canvas?.setActiveObject(newDormer)
+ } else {
+ const currentPoints = rectToPolygon(dormer)
+ dormer.points = currentPoints
}
canvas.renderAll()
}
diff --git a/src/hooks/option/useCanvasSetting.js b/src/hooks/option/useCanvasSetting.js
index 0f27f3e2..76f42075 100644
--- a/src/hooks/option/useCanvasSetting.js
+++ b/src/hooks/option/useCanvasSetting.js
@@ -31,32 +31,33 @@ import { dimensionLineSettingsState } from '@/store/commonUtilsAtom'
import { gridColorState } from '@/store/gridAtom'
import { useColor } from 'react-color-palette'
import { useMasterController } from '@/hooks/common/useMasterController'
-import { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting'
+import PlacementShapeSetting, { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting'
import { useCanvasMenu } from '../common/useCanvasMenu'
-import { menuTypeState } from '@/store/menuAtom'
import { usePopup } from '../usePopup'
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { useCommonCode } from '@/hooks/common/useCommonCode'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
+import { v4 as uuidv4 } from 'uuid'
+import { useEvent } from '@/hooks/useEvent'
const defaultDotLineGridSetting = {
INTERVAL: {
- type: 2, // 1: 가로,세로 간격 수동, 2: 비율 간격
+ type: 2 /* 1: 가로,세로 간격 수동, 2: 비율 간격 */,
ratioInterval: 910,
verticalInterval: 910,
horizontalInterval: 910,
- dimension: 1, // 치수
+ dimension: 1 /* 치수 */,
},
DOT: false,
LINE: false,
}
-let previousRoofMaterialsYn = 'N' // 지붕재 select 정보 비교 후 변경된 것이 없으면 1회만 실행
-
-export function useCanvasSetting() {
+// hook 추가 시 executeEffect를 인자로 받고 false일 경우 useEffect를 실행하지 않는다. default true
+// 아래 hook에 추가 된 함수만 사용하고 싶을 경우 false로 인자 전달
+export function useCanvasSetting(executeEffect = true) {
const canvas = useRecoilValue(canvasState)
- // canvas가 null이 아닐 때에만 getObjects 호출
+ /** canvas가 null이 아닐 때에만 getObjects 호출 */
const canvasObjects = canvas ? canvas.getObjects() : []
const [correntObjectNo, setCorrentObjectNo] = useRecoilState(correntObjectNoState)
@@ -87,7 +88,9 @@ export function useCanvasSetting() {
)
const [gridColor, setGridColor] = useRecoilState(gridColorState)
const [color, setColor] = useColor(gridColor ?? '#FF0000')
- const { menuNumber, setMenuNumber } = useCanvasMenu()
+ const { selectedMenu, setSelectedMenu } = useCanvasMenu()
+
+ const { initEvent } = useEvent()
const [settingsData, setSettingsData] = useState({
...settingModalFirstOptions,
@@ -115,17 +118,18 @@ export function useCanvasSetting() {
const [roofMaterials, setRoofMaterials] = useRecoilState(roofMaterialsAtom)
const [addedRoofs, setAddedRoofs] = useRecoilState(addedRoofsState)
const [fetchRoofMaterials, setFetchRoofMaterials] = useRecoilState(fetchRoofMaterialsState)
- const [type, setType] = useRecoilState(menuTypeState)
const setCurrentMenu = useSetRecoilState(currentMenuState)
- const resetModuleSelectionData = useResetRecoilState(moduleSelectionDataState) //다음으로 넘어가는 최종 데이터
- const resetSelectedModules = useResetRecoilState(selectedModuleState) //선택된 모듈
+ const resetModuleSelectionData = useResetRecoilState(moduleSelectionDataState) /* 다음으로 넘어가는 최종 데이터 */
+ const resetSelectedModules = useResetRecoilState(selectedModuleState) /* 선택된 모듈 */
const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2)
- const [raftCodes, setRaftCodes] = useState([]) // 서까래 정보
+ const [raftCodes, setRaftCodes] = useState([]) /* 서까래 정보 */
const { findCommonCode } = useCommonCode()
- const [currentRoof, setCurrentRoof] = useState(null) // 현재 선택된 지붕재 정보
+ const [currentRoof, setCurrentRoof] = useState(null) /* 현재 선택된 지붕재 정보 */
+ const { addPopup } = usePopup()
+ const [popupId, setPopupId] = useState(uuidv4())
const SelectOptions = [
{ id: 1, name: getMessage('modal.canvas.setting.grid.dot.line.setting.line.origin'), value: 1 },
@@ -136,56 +140,91 @@ export function useCanvasSetting() {
const selectedRoofMaterial = useRecoilValue(selectedRoofMaterialSelector) // 선택된 지붕재 정보
const { floorPlanState } = useContext(FloorPlanContext) // 플랜 상태
- const { closeAll } = usePopup() // 팝업 닫기
- const previousObjectNoRef = useRef(null) // 최초 데이터 설정 확인
- const previousRoofMaterialsRef = useRef(null) // 최초 데이터 설정 확인
+ const { closePopup, closeAll } = usePopup() // 팝업 닫기
useEffect(() => {
- const tempFetchRoofMaterials = !fetchRoofMaterials
-
- //최초 1회만 실행하도록 처리
- setFetchRoofMaterials(tempFetchRoofMaterials)
- if (tempFetchRoofMaterials) {
- addRoofMaterials()
+ if (!executeEffect) {
+ return
}
+
+ /** 초 1회만 실행하도록 처리 */
+ addRoofMaterials()
}, [])
- useEffect(() => {
- // 지붕재 select 정보가 존재해야 배치면초기설정 DB 정보 비교 후 지붕재 정보를 가져올 수 있음
- if (
- (!previousObjectNoRef.current && !correntObjectNo && previousObjectNoRef.current !== correntObjectNo) ||
- (roofMaterials.length !== 0 && JSON.stringify(previousRoofMaterialsRef.current) !== JSON.stringify(roofMaterials))
- ) {
- // 1회만 실행
- if (roofMaterials && previousRoofMaterialsYn === 'N') {
- if (correntObjectNo) {
- fetchBasicSettings()
- previousRoofMaterialsYn = 'Y'
- }
- }
-
- // 이전 값을 업데이트
- previousObjectNoRef.current = correntObjectNo
- previousRoofMaterialsRef.current = roofMaterials
+ /**
+ * 지붕재 초기세팅
+ */
+ const addRoofMaterials = async () => {
+ if (roofMaterials.length !== 0) {
+ return
}
- }, [roofMaterials, correntObjectNo])
+ const { data } = await getRoofMaterialList()
+
+ const roofLists = data.map((item, idx) => ({
+ ...item,
+ id: item.roofMatlCd,
+ name: item.roofMatlNm,
+ selected: idx === 0,
+ index: idx,
+ nameJp: item.roofMatlNmJp,
+ length: item.lenBase && parseInt(item.lenBase),
+ width: item.widBase && parseInt(item.widBase),
+ raft: item.raftBase && parseInt(item.raftBase),
+ layout: ['ROOF_ID_SLATE', 'ROOF_ID_SINGLE'].includes(item.roofMatlCd) ? ROOF_MATERIAL_LAYOUT.STAIRS : ROOF_MATERIAL_LAYOUT.PARALLEL,
+ hajebichi: item.roofPchBase && parseInt(item.roofPchBase),
+ pitch: item.pitch ? parseInt(item.pitch) : 4,
+ angle: item.angle ? parseInt(item.angle) : 21.8,
+ }))
+ setRoofMaterials(roofLists)
+ }
- //배치면 초기설정 화면이 열리지 않아도 데이터 set 하기 위해서 추가
useEffect(() => {
- if (addedRoofs.length > 0) {
+ if (!executeEffect) {
+ return
+ }
+ if (addedRoofs.length > 0 && addedRoofs[0].planNo === basicSetting.planNo) {
const raftCodeList = findCommonCode('203800')
setRaftCodes(raftCodeList)
-
- setCurrentRoof({ ...addedRoofs[0] })
+ setCurrentRoof({
+ ...addedRoofs[0],
+ planNo: addedRoofs[0].planNo,
+ roofSizeSet: String(basicSetting.roofSizeSet),
+ roofAngleSet: basicSetting.roofAngleSet,
+ })
}
}, [addedRoofs])
+ useEffect(() => {
+ if (!executeEffect) {
+ return
+ }
+ const selectedRoofMaterial = roofMaterials[0]
+
+ if (addedRoofs.length === 0) {
+ const newAddedRoofs = []
+ newAddedRoofs.push({ ...selectedRoofMaterial, selected: true, index: 0 })
+ setAddedRoofs(newAddedRoofs)
+ }
+ setBasicSettings({ ...basicSetting, selectedRoofMaterial: selectedRoofMaterial })
+ }, [roofMaterials])
+
useEffect(() => {
if (!canvas) {
return
}
+ if (!executeEffect) {
+ return
+ }
const { column } = corridorDimension
const lengthTexts = canvas.getObjects().filter((obj) => obj.name === 'lengthText')
+ const group = canvas.getObjects().filter((obj) => obj.type === 'group')
+ group.forEach((obj) => {
+ obj._objects
+ .filter((obj2) => obj2.name === 'lengthText')
+ .forEach((obj3) => {
+ lengthTexts.push(obj3)
+ })
+ })
switch (column) {
case 'corridorDimension':
@@ -212,41 +251,11 @@ export function useCanvasSetting() {
}, [corridorDimension])
useEffect(() => {
- if (settingsDataSave !== undefined) onClickOption2()
- }, [settingsData])
-
- //지붕재 초기세팅
- const addRoofMaterials = async () => {
- if (roofMaterials.length !== 0) {
+ if (!executeEffect) {
return
}
- const { data } = await getRoofMaterialList()
-
- const roofLists = data.map((item, idx) => ({
- ...item,
- id: item.roofMatlCd,
- name: item.roofMatlNm,
- selected: idx === 0,
- index: idx,
- nameJp: item.roofMatlNmJp,
- length: item.lenBase && parseInt(item.lenBase),
- width: item.widBase && parseInt(item.widBase),
- raft: item.raftBase && parseInt(item.raftBase),
- layout: ['ROOF_ID_SLATE', 'ROOF_ID_SINGLE'].includes(item.roofMatlCd) ? ROOF_MATERIAL_LAYOUT.STAIRS : ROOF_MATERIAL_LAYOUT.PARALLEL,
- hajebichi: item.roofPchBase && parseInt(item.roofPchBase),
- pitch: item.pitch ? parseInt(item.pitch) : 4,
- angle: item.angle ? parseInt(item.angle) : 21.8,
- }))
- setRoofMaterials(roofLists)
- const selectedRoofMaterial = roofLists[0]
-
- if (addedRoofs.length === 0) {
- const newAddedRoofs = []
- newAddedRoofs.push({ ...selectedRoofMaterial, selected: true, index: 0 })
- setAddedRoofs(newAddedRoofs)
- }
- setBasicSettings({ ...basicSetting, selectedRoofMaterial: selectedRoofMaterial })
- }
+ if (settingsDataSave !== undefined) onClickOption2()
+ }, [settingsData])
const getFonts = (itemValue) => {
if (!itemValue) return { id: 1, name: 'MS PGothic', value: 'MS PGothic' }
@@ -319,22 +328,28 @@ export function useCanvasSetting() {
}
}
- // 기본설정(PlacementShapeSetting) 조회 및 초기화
- const fetchBasicSettings = async () => {
+ /**
+ * 기본설정(PlacementShapeSetting) 조회 및 초기화
+ */
+ const fetchBasicSettings = async (planNo, openPoint) => {
try {
- await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${correntObjectNo}` }).then((res) => {
+ await get({
+ url: `/api/canvas-management/canvas-basic-settings/by-object/${correntObjectNo}/${planNo}`,
+ }).then((res) => {
let roofsRow = {}
let roofsArray = {}
if (res.length > 0) {
roofsRow = res.map((item) => {
return {
+ planNo: item.planNo,
roofSizeSet: String(item.roofSizeSet),
roofAngleSet: item.roofAngleSet,
}
})
roofsArray = res.map((item) => {
return {
+ planNo: item.planNo,
roofApply: item.roofApply,
roofSeq: item.roofSeq,
roofMatlCd: item.roofMatlCd,
@@ -347,9 +362,16 @@ export function useCanvasSetting() {
roofAngle: item.roofAngle,
}
})
+
+ /* 데이터 존재 시 화면 닫기(메뉴/저장 클릭 시 제외) */
+ if (openPoint !== 'canvasMenus' && openPoint !== 'basicSettingSave') {
+ //closePopup(popupId)
+ closeAll()
+ }
} else {
roofsRow = [
{
+ planNo: planNo,
roofSizeSet: '1',
roofAngleSet: 'slope',
},
@@ -357,6 +379,7 @@ export function useCanvasSetting() {
roofsArray = [
{
+ planNo: planNo,
roofApply: true,
roofSeq: 0,
roofMatlCd: 'ROOF_ID_WA_53A',
@@ -370,10 +393,23 @@ export function useCanvasSetting() {
},
]
- setMenuNumber(1)
+ /** 메뉴에서 배치면 초기설정 클릭 시 실행하지 않음 */
+ if (openPoint === null) {
+ /** 배치면 초기설정 미저장 상태이면 화면 열기 */
+ const placementInitialProps = {
+ id: popupId,
+ pos: {
+ x: 50,
+ y: 180,
+ },
+ planNo: planNo,
+ openPoint: 'useCanvasSetting',
+ }
+ addPopup(popupId, 1,
)
+ }
}
- // 데이터 설정
+ /** 데이터 설정 */
const addRoofs = []
for (let i = 0; i < roofsArray.length; i++) {
roofMaterials?.map((material) => {
@@ -387,6 +423,7 @@ export function useCanvasSetting() {
hajebichi: roofsArray[i].roofHajebichi,
raft: roofsArray[i].roofGap,
layout: roofsArray[i].roofLayout,
+ planNo: roofsRow[i].planNo,
roofSizeSet: roofsRow[i].roofSizeSet,
roofAngleSet: roofsRow[i].roofAngleSet,
pitch: roofsArray[i].roofPitch,
@@ -395,32 +432,64 @@ export function useCanvasSetting() {
}
})
}
- setAddedRoofs(addRoofs)
- setBasicSettings({
- ...basicSetting,
- roofMaterials: addRoofs[0],
- roofSizeSet: roofsRow[0].roofSizeSet,
- roofAngleSet: roofsRow[0].roofAngleSet,
- roofsData: roofsArray,
- selectedRoofMaterial: addRoofs.find((roof) => roof.selected),
- })
+
+ if (addRoofs.length > 0) {
+ setAddedRoofs(addRoofs)
+
+ setBasicSettings({
+ ...basicSetting,
+ roofMaterials: addRoofs[0],
+ planNo: roofsRow[0].planNo,
+ roofSizeSet: roofsRow[0].roofSizeSet,
+ roofAngleSet: roofsRow[0].roofAngleSet,
+ roofsData: roofsArray,
+ selectedRoofMaterial: addRoofs.find((roof) => roof.selected),
+ })
+
+ setCanvasSetting({
+ ...basicSetting,
+ roofMaterials: addRoofs[0],
+ planNo: roofsRow[0].planNo,
+ roofSizeSet: roofsRow[0].roofSizeSet,
+ roofAngleSet: roofsRow[0].roofAngleSet,
+ roofsData: roofsArray,
+ selectedRoofMaterial: addRoofs.find((roof) => roof.selected),
+ })
+ }
})
} catch (error) {
console.error('Data fetching error:', error)
}
- setCanvasSetting({ ...basicSetting })
+ // setCanvasSetting({ ...basicSetting })
}
- // 기본설정(PlacementShapeSetting) 저장
+ /**
+ * 저장/복사저장 시 지붕 크기에 따른 메뉴 설정
+ */
+ const setMenuByRoofSize = (roofSizeSet) => {
+ if (['2', '3'].includes(String(roofSizeSet))) {
+ setSelectedMenu('surface')
+ setCurrentMenu(MENU.BATCH_CANVAS.BATCH_DRAWING)
+ } else {
+ setSelectedMenu('outline')
+ setCurrentMenu(MENU.ROOF_COVERING.EXTERIOR_WALL_LINE)
+ }
+ }
+
+ /**
+ * 기본설정(PlacementShapeSetting) 저장
+ */
const basicSettingSave = async (params) => {
try {
const patternData = {
objectNo: correntObjectNo,
+ planNo: Number(params.planNo),
roofSizeSet: Number(params.roofSizeSet),
roofAngleSet: params.roofAngleSet,
roofMaterialsAddList: [
{
+ planNo: Number(params.planNo),
roofApply: true,
roofSeq: 0,
roofMatlCd:
@@ -437,42 +506,29 @@ export function useCanvasSetting() {
],
}
- //await post({ url: `/api/canvas-management/canvas-basic-settings`, data: patternData })
await post({ url: `/api/canvas-management/canvas-basic-settings`, data: patternData }).then((res) => {
- console.log('🚀 ~ basicSettingSave ~ res :', res)
-
swalFire({ text: getMessage(res.returnMessage) })
-
+ /** BasicSettings Recoil 설정 */
setBasicSettings({ ...params })
})
- //Recoil 설정
- setCanvasSetting({ ...basicSetting })
+ /** CanvasSetting Recoil 설정 - roofSizeSet을 문자열로 변환 */
+ setCanvasSetting({
+ ...basicSetting,
+ roofSizeSet: String(params.roofSizeSet),
+ })
- // 배치면초기설정 조회
- fetchBasicSettings()
+ /** 메뉴 설정 */
+ setMenuByRoofSize(params.roofSizeSet)
- // 메뉴 설정
- if (['2', '3'].includes(basicSetting?.roofSizeSet)) {
- setMenuNumber(3)
- setType('surface')
- setCurrentMenu(MENU.BATCH_CANVAS.BATCH_DRAWING)
- } else {
- setMenuNumber(2)
- setType('outline')
- setCurrentMenu(MENU.ROOF_COVERING.EXTERIOR_WALL_LINE)
- }
+ /** 배치면초기설정 조회 */
+ fetchBasicSettings(params.planNo, 'basicSettingSave')
- //모듈 선택 데이터 초기화
+ /** 모듈 선택 데이터 초기화 */
resetModuleSelectionData()
-
- // 모듈 선택 데이터 초기화
moduleSelectedDataTrigger({ common: {}, module: {}, roofConstructions: [] })
-
- // 모듈 선택 데이터 초기화
const isModuleExist = canvas.getObjects().some((obj) => obj.name === POLYGON_TYPE.MODULE)
if (!isModuleExist) {
- // 모듈 선택 데이터 초기화
resetSelectedModules()
}
} catch (error) {
@@ -480,11 +536,66 @@ export function useCanvasSetting() {
}
}
- // CanvasSetting 조회 및 초기화
+ /**
+ * 기본설정(PlacementShapeSetting) 복사 저장
+ */
+ const basicSettingCopySave = async (params) => {
+ try {
+ const patternData = {
+ objectNo: correntObjectNo,
+ planNo: Number(params.planNo),
+ roofSizeSet: Number(params.roofSizeSet),
+ roofAngleSet: params.roofAngleSet,
+ roofMaterialsAddList: params.roofsData.map((item) => ({
+ planNo: Number(item.planNo),
+ roofApply: item.roofApply,
+ roofSeq: item.roofSeq,
+ roofMatlCd: item.roofMatlCd,
+ roofWidth: item.roofWidth,
+ roofHeight: item.roofHeight,
+ roofHajebichi: item.roofHajebichi,
+ roofGap: item.roofGap,
+ roofLayout: item.roofLayout,
+ roofPitch: item.roofPitch,
+ roofAngle: item.roofAngle,
+ })),
+ }
+
+ await post({ url: `/api/canvas-management/canvas-basic-settings`, data: patternData }).then((res) => {
+ swalFire({ text: getMessage(res.returnMessage) })
+ })
+
+ /** CanvasSetting Recoil 설정 - roofSizeSet을 문자열로 변환 */
+ setCanvasSetting({
+ ...basicSetting,
+ roofSizeSet: String(params.roofSizeSet),
+ })
+
+ /** 메뉴 설정 */
+ setMenuByRoofSize(params.roofSizeSet)
+
+ /** 배치면초기설정 조회 */
+ fetchBasicSettings(Number(params.planNo), 'basicSettingSave')
+
+ /** 모듈 선택 데이터 초기화 */
+ resetModuleSelectionData()
+ // moduleSelectedDataTrigger({ common: {}, module: {}, roofConstructions: [] })
+ const isModuleExist = canvas.getObjects().some((obj) => obj.name === POLYGON_TYPE.MODULE)
+ if (!isModuleExist) {
+ resetSelectedModules()
+ }
+ } catch (error) {
+ swalFire({ text: error.message, icon: 'error' })
+ }
+ }
+
+ /**
+ * CanvasSetting 조회 및 초기화
+ */
const fetchSettings = async () => {
try {
+ initEvent()
const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${correntObjectNo}` })
- console.log('res', res)
if (Object.keys(res).length > 0) {
const optionData1 = settingModalFirstOptions.option1.map((item) => ({ ...item, selected: res[item.column] }))
@@ -493,16 +604,19 @@ export function useCanvasSetting() {
const optionData4 = settingModalSecondOptions.option4.map((item) => ({ ...item, selected: res[item.column] }))
const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({ ...item }))
- //흡착점 ON/OFF
+ /** 흡착점 ON/OFF */
setAdsorptionPointMode({ ...adsorptionPointMode, adsorptionPoint: res.adsorpPoint })
- //치수선 설정
+ /** 치수선 설정 */
setDimensionLineSettings({ ...dimensionLineSettings, pixel: res.originPixel, color: res.originColor })
- //도면크기 설정
+ /** 도면크기 설정 */
setPlanSizeSettingMode({ ...planSizeSettingMode, originHorizon: res.originHorizon, originVertical: res.originVertical })
+ canvas.setWidth(res.originHorizon)
+ canvas.setHeight(res.originVertical)
+ canvas.renderAll()
- // 데이터 설정
+ /** 데이터 설정 */
setSettingModalFirstOptions({
...settingModalFirstOptions,
option1: optionData1,
@@ -517,35 +631,35 @@ export function useCanvasSetting() {
const fontPatternData = {
commonText: {
- //문자 글꼴 조회 데이터
+ /** 문자 글꼴 조회 데이터 */
fontFamily: getFonts(res.wordFont),
fontWeight: getFontStyles(res.wordFontStyle),
fontSize: getFontSizes(res.wordFontSize),
fontColor: getFontColors(res.wordFontColor),
},
flowText: {
- //흐름방향 글꼴 조회 데이터
+ /** 흐름방향 글꼴 조회 데이터 */
fontFamily: getFonts(res.flowFont),
fontWeight: getFontStyles(res.flowFontStyle),
fontSize: getFontSizes(res.flowFontSize),
fontColor: getFontColors(res.flowFontColor),
},
dimensionLineText: {
- //치수 글꼴 조회 데이터
+ /** 치수 글꼴 조회 데이터 */
fontFamily: getFonts(res.dimensioFont),
fontWeight: getFontStyles(res.dimensioFontStyle),
fontSize: getFontSizes(res.dimensioFontSize),
fontColor: getFontColors(res.dimensioFontColor),
},
circuitNumberText: {
- //회로번호 글꼴 조회 데이터
+ /** 회로번호 글꼴 조회 데이터 */
fontFamily: getFonts(res.circuitNumFont),
fontWeight: getFontStyles(res.circuitNumFontStyle),
fontSize: getFontSizes(res.circuitNumFontSize),
fontColor: getFontColors(res.circuitNumFontColor),
},
lengthText: {
- //치수선 글꼴 조회 데이터
+ /** 치수선 글꼴 조회 데이터 */
fontFamily: getFonts(res.lengthFont),
fontWeight: getFontStyles(res.lengthFontStyle),
fontSize: getFontSizes(res.lengthFontSize),
@@ -553,10 +667,10 @@ export function useCanvasSetting() {
},
}
- //조회된 글꼴 데이터 set
+ /** 조회된 글꼴 데이터 set */
setGlobalFont(fontPatternData)
- //점/선 그리드
+ /** 점/선 그리드 */
const patternData = {
INTERVAL: {
type: res.gridType,
@@ -570,34 +684,32 @@ export function useCanvasSetting() {
}
setDotLineGridSettingState(patternData)
- //setCurrentSetting(patternData)
- //그리드 색 설정
+ /** 그리드 색 설정 */
setGridColor(res.gridColor)
} else {
- //조회된 글꼴 데이터가 없는 경우 (데이터 초기화)
+ /** 조회된 글꼴 데이터가 없는 경우 (데이터 초기화) */
- //흡착점 ON/OFF
+ /** 흡착점 ON/OFF */
setAdsorptionPointMode({ ...adsorptionPointMode, adsorptionPoint: false })
- //치수선 설정
+ /** 치수선 설정 */
resetDimensionLineSettings()
- //도면크기 설정
+ /** 도면크기 설정 */
resetPlanSizeSettingMode()
- // 데이터 설정
+ /** 데이터 설정 */
resetSettingModalFirstOptions()
resetSettingModalSecondOptions()
- // 데이터 초기화
+ /** 데이터 초기화 */
resetGlobalFont()
- //점/선 그리드
+ /** 점/선 그리드 */
setDotLineGridSettingState({ ...defaultDotLineGridSetting })
- //setCurrentSetting({ ...defaultDotLineGridSetting })
- //그리드 색 설정
+ /** 그리드 색 설정 */
setGridColor('#FF0000')
}
@@ -607,9 +719,11 @@ export function useCanvasSetting() {
}
}
- // CanvasSetting 옵션 클릭 후 저장
+ /**
+ * CanvasSetting 옵션 클릭 후 저장
+ */
const onClickOption2 = async () => {
- // 서버에 전송할 데이터
+ /** 서버에 전송할 데이터 */
const dataToSend = {
firstOption1: option1.map((item) => ({
column: item.column,
@@ -630,9 +744,9 @@ export function useCanvasSetting() {
})),
}
const patternData = {
- //견적서 번호
+ /** 견적서 번호 */
objectNo: correntObjectNo,
- //디스플레이 설정(다중)
+ /** 디스플레이 설정(다중) */
allocDisplay: dataToSend.firstOption1[0].selected,
outlineDisplay: dataToSend.firstOption1[1].selected,
gridDisplay: dataToSend.firstOption1[2].selected,
@@ -643,63 +757,62 @@ export function useCanvasSetting() {
trestleDisplay: dataToSend.firstOption1[7].selected,
imageDisplay: dataToSend.firstOption1[8].selected,
totalDisplay: dataToSend.firstOption1[9].selected,
- //차수 표시(단 건)
+ /** 차수 표시(단 건) */
corridorDimension: dataToSend.firstOption3[0].selected,
realDimension: dataToSend.firstOption3[1].selected,
noneDimension: dataToSend.firstOption3[2].selected,
- //화면 표시(단 건)
+ /** 화면 표시(단 건) */
onlyBorder: dataToSend.firstOption2[0].selected,
lineHatch: dataToSend.firstOption2[1].selected,
allPainted: dataToSend.firstOption2[2].selected,
- //흡착범위 설정(단 건)
+ /** 흡착범위 설정(단 건) */
adsorpRangeSmall: dataToSend.secondOption2[0].selected,
adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected,
adsorpRangeMedium: dataToSend.secondOption2[2].selected,
adsorpRangeLarge: dataToSend.secondOption2[3].selected,
-
- //흡착점 ON/OFF
+ /** 흡착점 ON/OFF */
adsorpPoint: adsorptionPointMode.adsorptionPoint,
//??: adsorptionRange, 사용여부 확인 필요
- //글꼴 설정
- //문자 글꼴
+ /** 문자 글꼴 설정 */
wordFont: globalFont.commonText.fontFamily?.value ?? 'MS PGothic',
wordFontStyle: globalFont.commonText.fontWeight?.value ?? 'normal',
wordFontSize: globalFont.commonText.fontSize?.value ?? 16,
wordFontColor: globalFont.commonText.fontColor?.value ?? 'black',
- //흐름방향 글꼴
+ /** 흐름방향 글꼴 설정 */
flowFont: globalFont.flowText.fontFamily?.value ?? 'MS PGothic',
flowFontStyle: globalFont.flowText.fontWeight?.value ?? 'normal',
flowFontSize: globalFont.flowText.fontSize?.value ?? 16,
flowFontColor: globalFont.flowText.fontColor?.value ?? 'black',
- //치수 글꼴
+ /** 치수 글꼴 설정 */
dimensioFont: globalFont.dimensionLineText.fontFamily?.value ?? 'MS PGothic',
dimensioFontStyle: globalFont.dimensionLineText.fontWeight?.value ?? 'normal',
dimensioFontSize: globalFont.dimensionLineText.fontSize?.value ?? 16,
dimensioFontColor: globalFont.dimensionLineText.fontColor?.value ?? 'black',
- //회로번호 글꼴
+ /** 회로번호 글꼴 설정 */
circuitNumFont: globalFont.circuitNumberText.fontFamily?.value ?? 'MS PGothic',
circuitNumFontStyle: globalFont.circuitNumberText.fontWeight?.value ?? 'normal',
circuitNumFontSize: globalFont.circuitNumberText.fontSize?.value ?? 16,
circuitNumFontColor: globalFont.circuitNumberText.fontColor?.value ?? 'black',
- //치수선 글꼴
+ /** 치수선 글꼴 설정 */
lengthFont: globalFont.lengthText.fontFamily?.value ?? 'MS PGothic',
lengthFontStyle: globalFont.lengthText.fontWeight?.value ?? 'normal',
lengthFontSize: globalFont.lengthText.fontSize?.value ?? 16,
lengthFontColor: globalFont.lengthText.fontColor?.value ?? 'black',
- //치수선 설정
+ /** 치수선 설정 */
originPixel: dimensionLineSettings.pixel,
originColor: dimensionLineSettings.color,
- //도면크기 설정
+ /** 도면크기 설정 */
originHorizon: planSizeSettingMode.originHorizon,
originVertical: planSizeSettingMode.originVertical,
+ /** 점/선 그리드 */
dotGridDisplay: dotLineGridSetting.DOT,
lineGridDisplay: dotLineGridSetting.LINE,
gridType: dotLineGridSetting.INTERVAL.type,
@@ -708,19 +821,23 @@ export function useCanvasSetting() {
gridRatio: dotLineGridSetting.INTERVAL.ratioInterval / 10,
gridDimen: dotLineGridSetting.INTERVAL.dimension,
+ /** 그리드 색 설정 */
gridColor: gridColor,
}
console.log('patternData ', patternData)
- // HTTP POST 요청 보내기
+ /**
+ * 저장 API 호출
+ */
await post({ url: `/api/canvas-management/canvas-settings`, data: patternData })
.then((res) => {
//swalFire({ text: getMessage(res.returnMessage) })
- // Canvas 디스플레이 설정 시 해당 옵션 적용
+ /** Canvas 디스플레이 설정 시 해당 옵션 적용 */
frontSettings()
- // 저장 후 재조회
+
+ /** 저장 후 재조회 */
fetchSettings()
})
.catch((error) => {
@@ -731,77 +848,76 @@ export function useCanvasSetting() {
//setAdsorptionRange(item.range)
}
- // Canvas 디스플레이 설정 시 해당 옵션 적용
+ /**
+ * Canvas 디스플레이 설정 시 해당 옵션 적용
+ */
const frontSettings = async () => {
const option1 = settingModalFirstOptions.option1
- // 'allocDisplay' 할당 표시
- // 'outlineDisplay' 외벽선 표시 'outerLine', POLYGON_TYPE.WALL
- // 'gridDisplay' 그리드 표시 'lindGrid', 'dotGrid'
- // 'lineDisplay' 지붕선 표시 'roof', POLYGON_TYPE.ROOF
- // 'wordDisplay' 문자 표시
- // 'circuitNumDisplay' 회로번호 표시
- // 'flowDisplay' 흐름방향 표시 'arrow', 'flowText'
- // 'trestleDisplay' 가대 표시
- // 'imageDisplay' 이미지 표시
- // 'totalDisplay' 집계표 표시
+ /**
+ * 'allocDisplay' 할당 표시
+ * 'outlineDisplay' 외벽선 표시 'outerLine', POLYGON_TYPE.WALL
+ * 'gridDisplay' 그리드 표시 'lindGrid', 'dotGrid'
+ * 'lineDisplay' 지붕선 표시 'roof', POLYGON_TYPE.ROOF
+ * 'wordDisplay' 문자 표시
+ * 'circuitNumDisplay' 회로번호 표시
+ * 'flowDisplay' 흐름방향 표시 'arrow', 'flowText'
+ * 'trestleDisplay' 가대 표시
+ * 'imageDisplay' 이미지 표시
+ * 'totalDisplay' 집계표 표시
+ */
- let optionName //옵션명
- let optionSelected //옵션상태
+ /**
+ * 옵션명 optionName
+ * 옵션상태 optionSelected
+ */
+ let optionName
+ let optionSelected
for (let i = 0; i < option1.length; i++) {
switch (option1[i].column) {
- case 'allocDisplay': //할당 표시
+ case 'allocDisplay':
optionName = []
break
- case 'outlineDisplay': //외벽선 표시
+ case 'outlineDisplay':
optionName = ['outerLine', POLYGON_TYPE.WALL]
break
- case 'gridDisplay': //그리드 표시
+ case 'gridDisplay':
optionName = ['lindGrid', 'dotGrid', 'tempGrid']
break
- case 'lineDisplay': //지붕선 표시
+ case 'lineDisplay':
optionName = ['roof', POLYGON_TYPE.ROOF]
break
- case 'wordDisplay': //문자 표시
+ case 'wordDisplay':
optionName = ['commonText']
break
- case 'circuitNumDisplay': //회로번호 표시
+ case 'circuitNumDisplay':
optionName = ['circuitNumber']
break
- case 'flowDisplay': //흐름방향 표시
+ case 'flowDisplay':
optionName = ['arrow', 'flowText']
break
- case 'trestleDisplay': //가대 표시
+ case 'trestleDisplay':
optionName = ['rack', 'smartRack', 'bracket', 'eaveBar', 'halfEaveBar']
break
- case 'imageDisplay': //이미지 표시
- optionName = ['9']
+ case 'imageDisplay':
+ optionName = ['backGroundImage']
break
- case 'totalDisplay': //집계표 표시
- // 작업할 필요 없음
+ case 'totalDisplay':
+ /** 작업할 필요 없음 */
optionName = []
break
}
- // 표시 선택 상태(true/false)
+ /** 표시 선택 상태(true/false)*/
optionSelected = option1[i].selected
- //canvas.getObjects() >> canvasObjects
canvasObjects
.filter((obj) => optionName.includes(obj.name))
- //.filter((obj) => obj.name === optionName)
.forEach((obj) => {
obj.set({ visible: optionSelected })
- //obj.set({ visible: !obj.visible })
})
canvas?.renderAll()
-
- // console.log(
- // 'optionName',
- // optionName,
- // canvas.getObjects().filter((obj) => optionName.includes(obj.name)),
- // )
}
}
@@ -818,6 +934,7 @@ export function useCanvasSetting() {
setAdsorptionRange,
fetchSettings,
fetchBasicSettings,
+ basicSettingCopySave,
frontSettings,
globalFont,
setGlobalFont,
diff --git a/src/hooks/roofcover/useAuxiliaryDrawing.js b/src/hooks/roofcover/useAuxiliaryDrawing.js
index 7cacdd03..6023bce8 100644
--- a/src/hooks/roofcover/useAuxiliaryDrawing.js
+++ b/src/hooks/roofcover/useAuxiliaryDrawing.js
@@ -22,6 +22,7 @@ import { useSwal } from '@/hooks/useSwal'
import { usePopup } from '@/hooks/usePopup'
import { calculateAngle, isSamePoint } from '@/util/qpolygon-utils'
import { POLYGON_TYPE } from '@/common/common'
+import { useMessage } from '../useMessage'
// 보조선 작성
export function useAuxiliaryDrawing(id, isUseEffect = true) {
@@ -34,6 +35,7 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
const { swalFire } = useSwal()
const { getAdsorptionPoints } = useAdsorptionPoint()
const { closePopup } = usePopup()
+ const { getMessage } = useMessage()
const adsorptionRange = useRecoilValue(adsorptionRangeState)
@@ -104,6 +106,10 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
}, [])
useEffect(() => {
+ const roofs = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
+ if (roofs.length === 0) {
+ return
+ }
addCanvasMouseEventListener('mouse:down', mouseDown)
}, [verticalHorizontalMode])
@@ -129,6 +135,7 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
const copy = (object, x, y) => {
return addLine([object.x1 + x, object.y1 + y, object.x2 + x, object.y2 + y], {
+ attributes: object.attributes,
stroke: 'red',
strokeWidth: 1,
selectable: true,
@@ -406,7 +413,7 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
const length1Value = length1Ref.current.value
if (diagonalLength <= length1Value) {
- alert('대각선 길이는 직선 길이보다 길어야 합니다.')
+ // alert('대각선 길이는 직선 길이보다 길어야 합니다.')
return
}
@@ -827,7 +834,8 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
}
const handleFix = () => {
- if (!confirm('지붕선 완료하시겠습니까?')) {
+ // if (!confirm('보조선 작성을 완료하시겠습니까?')) {
+ if (!confirm(getMessage('want.to.complete.auxiliary.creation'))) {
return
}
diff --git a/src/hooks/roofcover/useEavesGableEdit.js b/src/hooks/roofcover/useEavesGableEdit.js
index 7e84994e..ff0073ae 100644
--- a/src/hooks/roofcover/useEavesGableEdit.js
+++ b/src/hooks/roofcover/useEavesGableEdit.js
@@ -190,6 +190,8 @@ export function useEavesGableEdit(id) {
convertPolygonToLines(wallLine)
})
+ canvas.renderAll()
+
addCanvasMouseEventListener('mouse:over', mouseOverEvent)
addCanvasMouseEventListener('mouse:down', mouseDownEvent)
}
diff --git a/src/hooks/roofcover/useOuterLineWall.js b/src/hooks/roofcover/useOuterLineWall.js
index a1292ccf..facebd71 100644
--- a/src/hooks/roofcover/useOuterLineWall.js
+++ b/src/hooks/roofcover/useOuterLineWall.js
@@ -559,7 +559,7 @@ export function useOuterLineWall(id, propertiesId) {
const length1Value = length1Ref.current.value
if (diagonalLength <= length1Value) {
- alert('대각선 길이는 직선 길이보다 길어야 합니다.')
+ // alert('대각선 길이는 직선 길이보다 길어야 합니다.')
return
}
@@ -880,7 +880,7 @@ export function useOuterLineWall(id, propertiesId) {
})
if (isAllRightAngle) {
- alert('부정확한 다각형입니다.')
+ // alert('부정확한 다각형입니다.')
return
}
diff --git a/src/hooks/roofcover/usePropertiesSetting.js b/src/hooks/roofcover/usePropertiesSetting.js
index 564ec3e8..dd5ca91a 100644
--- a/src/hooks/roofcover/usePropertiesSetting.js
+++ b/src/hooks/roofcover/usePropertiesSetting.js
@@ -11,6 +11,8 @@ import PropertiesSetting from '@/components/floor-plan/modal/outerlinesetting/Pr
import RoofShapeSetting from '@/components/floor-plan/modal/roofShape/RoofShapeSetting'
import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting'
import { settingModalFirstOptionsState } from '@/store/settingAtom'
+import { useSwal } from '@/hooks/useSwal'
+import { useMessage } from '@/hooks/useMessage'
// 외벽선 속성 설정
export function usePropertiesSetting(id) {
@@ -25,6 +27,8 @@ export function usePropertiesSetting(id) {
const { addPolygonByLines } = usePolygon()
const { removeLine, hideLine } = useLine()
const { addPopup, closePopup } = usePopup()
+ const { swalFire } = useSwal()
+ const { getMessage } = useMessage()
useEffect(() => {
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
@@ -125,67 +129,77 @@ export function usePropertiesSetting(id) {
}
const handleFix = () => {
- const isClose = confirm('외벽선 속성 설정을 완료하시겠습니까?')
- if (isClose) {
- const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
+ swalFire({
+ text: getMessage('outerLine.property.fix'),
+ type: 'confirm',
+ confirmFn: async () => {
+ const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
+
+ const notSetAttributes = lines.filter((line) => !line.attributes?.type)
+ if (notSetAttributes.length > 0) {
+ // 세팅이 하나라도 안되어있으면 초기화
+ lines.forEach((line) => {
+ line.set({
+ stroke: '#000000',
+ strokeWidth: 4,
+ })
+ })
+ canvas.discardActiveObject()
+ // closePopup(id)
+ addPopup(id, 1,
)
+ return
+ }
- const notSetAttributes = lines.filter((line) => !line.attributes?.type)
- if (notSetAttributes.length > 0) {
- // 세팅이 하나라도 안되어있으면 초기화
lines.forEach((line) => {
line.set({
+ attributes: line.attributes ? line.attributes : { offset: 0, type: LINE_TYPE.WALLLINE.WALL },
+ stroke: '#000000',
+ strokeWidth: 4,
+ })
+
+ hideLine(line)
+ })
+
+ const wall = addPolygonByLines(lines, { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' })
+
+ wall.lines = [...lines]
+
+ const roof = drawRoofPolygon(wall)
+
+ setPoints([])
+ canvas.renderAll()
+ roof.drawHelpLine(settingModalFirstOptions)
+ addPopup(id, 1,
)
+ },
+ denyFn: async () => {
+ return
+ },
+ })
+ }
+
+ const closeModal = (fn) => {
+ swalFire({
+ text: getMessage('outerLine.property.fix'),
+ type: 'confirm',
+ confirmFn: async () => {
+ const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
+
+ lines.forEach((line) => {
+ line.set({
+ attributes: { offset: 0, type: LINE_TYPE.WALLLINE.WALL },
stroke: '#000000',
strokeWidth: 4,
})
})
- canvas.discardActiveObject()
- // closePopup(id)
- addPopup(id, 1,
)
+
+ canvas.renderAll()
+ setPoints([])
+ closePopup(id)
+ },
+ denyFn: async () => {
return
- }
-
- lines.forEach((line) => {
- line.set({
- attributes: line.attributes ? line.attributes : { offset: 0, type: LINE_TYPE.WALLLINE.WALL },
- stroke: '#000000',
- strokeWidth: 4,
- })
-
- hideLine(line)
- })
-
- const wall = addPolygonByLines(lines, { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' })
-
- wall.lines = [...lines]
-
- const roof = drawRoofPolygon(wall)
-
- setPoints([])
- canvas.renderAll()
- roof.drawHelpLine(settingModalFirstOptions)
- addPopup(id, 1,
)
- return
- }
- }
-
- const closeModal = (fn) => {
- if (!confirm('외벽선 속성 설정을 종료 하시겠습니까?')) {
- return
- }
-
- const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
-
- lines.forEach((line) => {
- line.set({
- attributes: { offset: 0, type: LINE_TYPE.WALLLINE.WALL },
- stroke: '#000000',
- strokeWidth: 4,
- })
+ },
})
-
- canvas.renderAll()
- setPoints([])
- closePopup(id)
}
return { handleSetEaves, handleSetGable, handleRollback, handleFix, closeModal }
diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js
index 34ec3f13..536a2127 100644
--- a/src/hooks/roofcover/useRoofAllocationSetting.js
+++ b/src/hooks/roofcover/useRoofAllocationSetting.js
@@ -19,7 +19,6 @@ import ActualSizeSetting from '@/components/floor-plan/modal/roofAllocation/Actu
import { useMessage } from '@/hooks/useMessage'
import useMenu from '@/hooks/common/useMenu'
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
-import { menuTypeState } from '@/store/menuAtom'
import { useRoofFn } from '@/hooks/common/useRoofFn'
import { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting'
import { globalLocaleStore } from '@/store/localeAtom'
@@ -28,7 +27,6 @@ import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { outerLinePointsState } from '@/store/outerLineAtom'
-// 지붕면 할당
export function useRoofAllocationSetting(id) {
const canvas = useRecoilValue(canvasState)
const [correntObjectNo, setCorrentObjectNo] = useRecoilState(correntObjectNoState)
@@ -37,13 +35,12 @@ export function useRoofAllocationSetting(id) {
const [popupId, setPopupId] = useState(uuidv4())
const { addPopup, closePopup, closeAll } = usePopup()
const currentObject = useRecoilValue(currentObjectState)
- const { setMenuNumber } = useCanvasMenu()
- const setMenuType = useSetRecoilState(menuTypeState)
+ const { setSelectedMenu } = useCanvasMenu()
const roofMaterials = useRecoilValue(roofMaterialsSelector)
const selectedRoofMaterial = useRecoilValue(selectedRoofMaterialSelector)
const [basicSetting, setBasicSetting] = useRecoilState(basicSettingState)
- const [currentRoofMaterial, setCurrentRoofMaterial] = useState(roofMaterials[0]) // 팝업 내 기준 지붕재
- const [roofList, setRoofList] = useRecoilState(addedRoofsState) // 배치면 초기설정에서 선택한 지붕재 배열
+ const [currentRoofMaterial, setCurrentRoofMaterial] = useState(roofMaterials[0]) /** 팝업 내 기준 지붕재 */
+ const [roofList, setRoofList] = useRecoilState(addedRoofsState) /** 배치면 초기설정에서 선택한 지붕재 배열 */
const [editingLines, setEditingLines] = useState([])
const [currentRoofList, setCurrentRoofList] = useState([])
const currentAngleType = useRecoilValue(currentAngleTypeSelector)
@@ -59,14 +56,17 @@ export function useRoofAllocationSetting(id) {
const resetPoints = useResetRecoilState(outerLinePointsState)
useEffect(() => {
+ /** 배치면 초기설정에서 선택한 지붕재 배열 설정 */
setCurrentRoofList(roofList)
}, [])
useEffect(() => {
- const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) // roofPolygon.innerLines
+ /** 지붕면 조회 */
+ const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) /** roofPolygon.innerLines */
roofBases.forEach((roof) => {
roof.innerLines.forEach((line) => {
+ /** 실측값이 없는 경우 라인 두께 4로 설정 */
if (!line.attributes.actualSize || line.attributes?.actualSize === 0) {
line.set({
strokeWidth: 4,
@@ -75,6 +75,7 @@ export function useRoofAllocationSetting(id) {
})
}
+ /** 현재 선택된 라인인 경우 라인 두께 2로 설정 */
if (editingLines.includes(line)) {
line.set({
strokeWidth: 2,
@@ -84,6 +85,8 @@ export function useRoofAllocationSetting(id) {
}
})
})
+
+ /** 현재 선택된 객체가 보조라인, 피라미드, 힙인 경우 두께 4로 설정 */
if (currentObject && currentObject.name && ['auxiliaryLine', 'ridge', 'hip'].includes(currentObject.name)) {
currentObject.set({
strokeWidth: 4,
@@ -93,26 +96,31 @@ export function useRoofAllocationSetting(id) {
}, [currentObject])
useEffect(() => {
- // canvas.getObjects().filter((obj) => obj.type === 'QLine')
+ /** 현재 선택된 객체가 보조라인, 피라미드, 힙인 경우 두께 4로 설정 */
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
if (roofBases.length === 0) {
swalFire({ text: '할당할 지붕이 없습니다.' })
closePopup(id)
}
- fetchBasicSettings()
+ /** 배치면 초기설정 조회 */
+ fetchBasicSettings(basicSetting.planNo)
}, [])
- // 지붕면 할당 조회 및 초기화
- const fetchBasicSettings = async () => {
+ /**
+ * 배치면 초기설정 조회
+ */
+ const fetchBasicSettings = async (planNo) => {
try {
- await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${correntObjectNo}` }).then((res) => {
- console.log('🚀 ~ useRoofAllocationSetting ~ fetchBasicSettings ~ res >>>>>>>>>>>>>>>>>>>>> :', res)
+ await get({
+ url: `/api/canvas-management/canvas-basic-settings/by-object/${correntObjectNo}/${planNo}`,
+ }).then((res) => {
let roofsArray = {}
if (res.length > 0) {
roofsArray = res.map((item) => {
return {
+ planNo: item.planNo,
roofApply: item.roofApply,
roofSeq: item.roofSeq,
roofMatlCd: item.roofMatlCd,
@@ -128,6 +136,7 @@ export function useRoofAllocationSetting(id) {
} else {
roofsArray = [
{
+ planNo: planNo,
roofApply: true,
roofSeq: 0,
roofMatlCd: 'ROOF_ID_WA_53A',
@@ -142,11 +151,9 @@ export function useRoofAllocationSetting(id) {
]
}
- console.log('fetchBasicSettings roofsArray', roofsArray)
-
- console.log(roofsArray)
-
- // 데이터 설정
+ /**
+ * 데이터 설정
+ */
const selectRoofs = []
for (let i = 0; i < roofsArray.length; i++) {
roofMaterials?.map((material) => {
@@ -168,16 +175,17 @@ export function useRoofAllocationSetting(id) {
})
}
- // setCurrentRoofList(selectRoofs)
- //setBasicSetting({ ...basicSetting, roofsData: roofsArray })
setBasicSetting({
...basicSetting,
+ planNo: res[0].planNo,
roofSizeSet: res[0].roofSizeSet,
roofAngleSet: res[0].roofAngleSet,
roofsData: roofsArray,
selectedRoofMaterial: selectRoofs.find((roof) => roof.selected),
})
+
setBasicInfo({
+ planNo: '' + res[0].planNo,
roofSizeSet: '' + res[0].roofSizeSet,
roofAngleSet: '' + res[0].roofAngleSet,
})
@@ -187,14 +195,18 @@ export function useRoofAllocationSetting(id) {
}
}
- // 지붕면 할당 저장
+ /**
+ * 지붕면 할당 저장
+ */
const basicSettingSave = async () => {
try {
const patternData = {
objectNo: correntObjectNo,
+ planNo: Number(basicSetting.planNo),
roofSizeSet: Number(basicSetting.roofSizeSet),
roofAngleSet: basicSetting.roofAngleSet,
roofAllocationList: currentRoofList.map((item, index) => ({
+ planNo: Number(basicSetting.planNo),
roofApply: item.selected,
roofSeq: index,
roofMatlCd: item.roofMatlCd === null || item.roofMatlCd === undefined ? 'ROOF_ID_WA_53A' : item.roofMatlCd,
@@ -208,24 +220,26 @@ export function useRoofAllocationSetting(id) {
})),
}
- console.log('🚀 ~ basicSettingSave ~ patternData >>>>>>>>>>>>> :', patternData)
-
await post({ url: `/api/canvas-management/roof-allocation-settings`, data: patternData }).then((res) => {
- console.log('roof-allocation-settings res ', res)
swalFire({ text: getMessage(res.returnMessage) })
})
//Recoil 설정
//setCanvasSetting({ ...basicSetting })
- fetchBasicSettings()
+
+ /** 배치면 초기설정 조회 */
+ fetchBasicSettings(basicSetting.planNo)
} catch (error) {
swalFire({ text: error.message, icon: 'error' })
}
}
+ /**
+ * 지붕재 추가
+ */
const onAddRoofMaterial = () => {
if (currentRoofList.length >= 4) {
- swalFire({ type: 'alert', icon: 'error', text: getMessage('지붕재는 4개까지 선택 가능합니다.') })
+ swalFire({ type: 'alert', icon: 'error', text: getMessage('roof.exceed.count') })
return
}
setCurrentRoofList([
@@ -240,6 +254,9 @@ export function useRoofAllocationSetting(id) {
])
}
+ /**
+ * 지붕재 삭제
+ */
const onDeleteRoofMaterial = (idx) => {
const isSelected = currentRoofList[idx].selected
const newRoofList = JSON.parse(JSON.stringify(currentRoofList)).filter((_, index) => index !== idx)
@@ -249,11 +266,15 @@ export function useRoofAllocationSetting(id) {
setCurrentRoofList(newRoofList)
}
- // 선택한 지붕재로 할당
+ /**
+ * 선택한 지붕재로 할당
+ */
const handleSave = () => {
basicSettingSave()
- // 모두 actualSize 있으면 바로 적용 없으면 actualSize 설정
+ /**
+ * 모두 actualSize 있으면 바로 적용 없으면 actualSize 설정
+ */
if (checkInnerLines()) {
addPopup(popupId, 1, )
} else {
@@ -262,11 +283,13 @@ export function useRoofAllocationSetting(id) {
}
}
- // 지붕재 오른쪽 마우스 클릭 후 단일로 지붕재 변경 필요한 경우
+ /**
+ * 지붕재 오른쪽 마우스 클릭 후 단일로 지붕재 변경 필요한 경우
+ */
const handleSaveContext = () => {
basicSettingSave()
const newRoofList = currentRoofList.map((roof, idx) => {
- return { ...roof, index: idx }
+ return { ...roof, index: idx, raft: roof.raft ? roof.raft : roof.raftBaseCd }
})
setBasicSetting((prev) => {
return {
@@ -283,6 +306,9 @@ export function useRoofAllocationSetting(id) {
closeAll()
}
+ /**
+ * 지붕면 할당
+ */
const handleAlloc = () => {
if (!checkInnerLines()) {
apply()
@@ -295,6 +321,9 @@ export function useRoofAllocationSetting(id) {
}
}
+ /**
+ * 실측값 없는 경우 체크
+ */
const checkInnerLines = () => {
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) // roofPolygon.innerLines
let result = false
@@ -318,6 +347,9 @@ export function useRoofAllocationSetting(id) {
return result
}
+ /**
+ * 지붕면 할당
+ */
const apply = () => {
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF && !obj.roofMaterial)
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
@@ -331,6 +363,8 @@ export function useRoofAllocationSetting(id) {
} catch (e) {
return
}
+
+ /** 라인 삭제 */
roofBase.innerLines.forEach((line) => {
canvas.remove(line)
})
@@ -338,12 +372,14 @@ export function useRoofAllocationSetting(id) {
canvas.remove(roofBase)
})
+ /** 벽면 삭제 */
wallLines.forEach((wallLine) => {
canvas.remove(wallLine)
})
+ /** 데이터 설정 */
const newRoofList = currentRoofList.map((roof, idx) => {
- return { ...roof, index: idx, ...basicInfo }
+ return { ...roof, index: idx, ...basicInfo, raft: roof.raft ? roof.raft : roof.raftBaseCd }
})
setBasicSetting((prev) => {
@@ -361,6 +397,8 @@ export function useRoofAllocationSetting(id) {
roof.set({
isFixed: true,
})
+
+ /** 모양 패턴 설정 */
setSurfaceShapePattern(
roof,
roofDisplay.column,
@@ -370,18 +408,22 @@ export function useRoofAllocationSetting(id) {
drawDirectionArrow(roof)
})
+ /** 외곽선 삭제 */
const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'outerLinePoint' || obj.name === 'outerLine')
removeTargets.forEach((obj) => {
canvas.remove(obj)
})
setEditingLines([])
closeAll()
- setMenuNumber(3)
- setMenuType('surface')
+ setSelectedMenu('surface')
+ /** 모듈 선택 데이터 초기화 */
modifyModuleSelectionData()
}
+ /**
+ * 라인 사이즈 설정
+ */
const setLineSize = (id, size) => {
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
roofBases.forEach((roof) => {
@@ -400,14 +442,14 @@ export function useRoofAllocationSetting(id) {
canvas?.renderAll()
}
- // 지붕재 변경
+ /**
+ * 지붕재 변경
+ */
const handleChangeRoofMaterial = (value, index) => {
- const selectedIndex = roofMaterials.findIndex((roof) => roof.selected)
-
const selectedRoofMaterial = roofMaterials.find((roof) => roof.roofMatlCd === value.id)
const newRoofList = currentRoofList.map((roof, idx) => {
if (idx === index) {
- return { ...selectedRoofMaterial }
+ return { ...selectedRoofMaterial, selected: roof.selected }
}
return roof
})
@@ -415,7 +457,9 @@ export function useRoofAllocationSetting(id) {
setCurrentRoofList(newRoofList)
}
- // 기본 지붕재 radio값 변경
+ /**
+ * 기본 지붕재 radio값 변경
+ */
const handleDefaultRoofMaterial = (index) => {
const newRoofList = currentRoofList.map((roof, idx) => {
return { ...roof, selected: idx === index }
@@ -424,7 +468,9 @@ export function useRoofAllocationSetting(id) {
setCurrentRoofList(newRoofList)
}
- // 서까래 변경
+ /**
+ * 서까래 변경
+ */
const handleChangeRaft = (e, index) => {
const raftValue = e.clCode
@@ -438,6 +484,9 @@ export function useRoofAllocationSetting(id) {
setCurrentRoofList(newRoofList)
}
+ /**
+ * 레이아웃 변경
+ */
const handleChangeLayout = (layoutValue, index) => {
const newRoofList = currentRoofList.map((roof, idx) => {
if (idx === index) {
@@ -449,44 +498,11 @@ export function useRoofAllocationSetting(id) {
setCurrentRoofList(newRoofList)
}
+ /**
+ * 치수 입력방법(복시도입력/실측값입력/육지붕)
+ */
const handleChangeInput = (e, type = '', index) => {
const value = e.target.value
- /*if (type === 'pitch') {
- // type이 pitch인 경우 소수점 1자리까지만 입력 가능
- const reg = /^[0-9]+(\.[0-9]{0,1})?$/
-
- if (!reg.test(value)) {
- e.target.value = value.substring(0, value.length - 1)
- const newRoofList = currentRoofList.map((roof, idx) => {
- if (idx === index) {
- return {
- ...roof,
- [type]: currentAngleType === 'slope' ? value.substring(0, value.length - 1) : getChonByDegree(value.substring(0, value.length - 1)),
- }
- }
- return roof
- })
-
- setCurrentRoofList(newRoofList)
-
- return
- } else {
- const newRoofList = currentRoofList.map((roof, idx) => {
- if (idx === index) {
- return {
- ...roof,
- [type]: currentAngleType === 'slope' ? value : getChonByDegree(value),
- }
- }
- return roof
- })
-
- setCurrentRoofList(newRoofList)
- }
-
- return
- }*/
-
const newRoofList = currentRoofList.map((roof, idx) => {
if (idx === index) {
return { ...roof, [type]: value }
@@ -497,6 +513,9 @@ export function useRoofAllocationSetting(id) {
setCurrentRoofList(newRoofList)
}
+ /**
+ * 피치 변경
+ */
const handleChangePitch = (e, index) => {
let value = e.target.value
@@ -516,7 +535,9 @@ export function useRoofAllocationSetting(id) {
setCurrentRoofList(newRoofList)
}
- // 모듈 선택에서 선택한 데이터 초기화
+ /**
+ * 모듈 선택에서 선택한 데이터 초기화
+ */
const modifyModuleSelectionData = () => {
if (moduleSelectionData.roofConstructions.length > 0) {
setModuleSelectionData({ ...moduleSelectionData, roofConstructions: [] })
@@ -524,6 +545,9 @@ export function useRoofAllocationSetting(id) {
}
}
+ /**
+ * 모듈 선택 데이터 트리거
+ */
const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2)
return {
diff --git a/src/hooks/roofcover/useRoofShapeSetting.js b/src/hooks/roofcover/useRoofShapeSetting.js
index ea21aecb..f1139366 100644
--- a/src/hooks/roofcover/useRoofShapeSetting.js
+++ b/src/hooks/roofcover/useRoofShapeSetting.js
@@ -1,6 +1,6 @@
import { useEffect, useRef, useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
-import { useRecoilValue, useSetRecoilState } from 'recoil'
+import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, currentMenuState, currentObjectState, pitchTextSelector } from '@/store/canvasAtom'
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
import { usePolygon } from '@/hooks/usePolygon'
@@ -9,9 +9,17 @@ import { useLine } from '@/hooks/useLine'
import { outerLineFixState } from '@/store/outerLineAtom'
import { useSwal } from '@/hooks/useSwal'
import { usePopup } from '@/hooks/usePopup'
-import { getChonByDegree } from '@/util/canvas-util'
+import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util'
import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting'
-import { settingModalFirstOptionsState } from '@/store/settingAtom'
+import {
+ addedRoofsState,
+ basicSettingState,
+ correntObjectNoState,
+ selectedRoofMaterialSelector,
+ settingModalFirstOptionsState,
+} from '@/store/settingAtom'
+import { useAxios } from '@/hooks/useAxios'
+import { globalLocaleStore } from '@/store/localeAtom'
// 지붕형상 설정
export function useRoofShapeSetting(id) {
@@ -23,15 +31,16 @@ export function useRoofShapeSetting(id) {
const currentAngleType = useRecoilValue(currentAngleTypeSelector)
const pitchText = useRecoilValue(pitchTextSelector)
const { addPolygonByLines } = usePolygon()
+ const selectedRoofMaterial = useRecoilValue(selectedRoofMaterialSelector)
- const [pitch, setPitch] = useState(currentAngleType === ANGLE_TYPE.SLOPE ? 4 : 21.8) // 경사
+ const [pitch, setPitch] = useState(currentAngleType === ANGLE_TYPE.SLOPE ? selectedRoofMaterial.pitch : selectedRoofMaterial.angle) // 경사
const [eavesOffset, setEavesOffset] = useState(500) // 처마출폭
const [gableOffset, setGableOffset] = useState(300) // 케라바출폭
const [sleeveOffset, setSleeveOffset] = useState(300) // 소매출폭
const [jerkinHeadWidth, setJerkinHeadWidth] = useState(800) // 반절처 폭
const [jerkinHeadPitch, setJerkinHeadPitch] = useState(currentAngleType === ANGLE_TYPE.SLOPE ? 4.5 : 20) // 반절처 경사
const [hipAndGableWidth, setHipAndGableWidth] = useState(800) // 팔작지붕 폭
- const [shedPitch, setShedPitch] = useState(currentAngleType === ANGLE_TYPE.SLOPE ? 4 : 21.8) // 팔작지붕 폭
+ const [shedPitch, setShedPitch] = useState(currentAngleType === ANGLE_TYPE.SLOPE ? selectedRoofMaterial.pitch : selectedRoofMaterial.angle) // 팔작지붕 폭
const [shedWidth, setShedWidth] = useState(300) // 한쪽흐름 폭
const [hasSleeve, setHasSleeve] = useState('0')
const currentObject = useRecoilValue(currentObjectState)
@@ -52,6 +61,13 @@ export function useRoofShapeSetting(id) {
const settingModalFirstOptions = useRecoilValue(settingModalFirstOptionsState)
+ const [addedRoofs, setAddedRoofs] = useRecoilState(addedRoofsState)
+
+ const [basicSetting, setBasicSetting] = useRecoilState(basicSettingState)
+ const correntObjectNo = useRecoilValue(correntObjectNoState)
+ const globalLocaleState = useRecoilValue(globalLocaleStore)
+ const { post } = useAxios(globalLocaleState)
+
useEffect(() => {
pitchRef.current = currentAngleType === ANGLE_TYPE.SLOPE ? pitch : getChonByDegree(pitch)
}, [pitch])
@@ -165,6 +181,11 @@ export function useRoofShapeSetting(id) {
return
}
+ if ([1, 2, 3, 5, 6, 7, 8].includes(shapeNum)) {
+ // 변별로 설정이 아닌 경우 경사를 지붕재에 적용해주어야함
+ setRoofPitch()
+ }
+
switch (shapeNum) {
case 1: {
outerLines = saveRidge()
@@ -180,9 +201,13 @@ export function useRoofShapeSetting(id) {
}
case 4: {
outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
-
+ let isValid = outerLines.every((line) => line.attributes?.isFixed)
+ if (!isValid) {
+ swalFire({ text: getMessage('modal.canvas.setting.roofline.properties.setting.not.setting'), type: 'alert', icon: 'warning' })
+ return
+ }
const pitch = outerLines.find((line) => line.attributes.type === LINE_TYPE.WALLLINE.SHED)?.attributes.pitch
- let isValid = outerLines.every((line) => line.attributes.isFixed)
+
// 변별로 설정중 한쪽흐름일 경우 한쪽흐름의 pitch로 설정
if (pitch) {
outerLines.forEach((line) => {
@@ -195,10 +220,6 @@ export function useRoofShapeSetting(id) {
}
})
}
- if (!isValid) {
- swalFire({ text: '설정이 완료되지 않았습니다.', icon: 'error' })
- return
- }
break
}
@@ -465,6 +486,62 @@ export function useRoofShapeSetting(id) {
canvas.remove(tempPolygon)
}
+ // 저장된 경사를 addedRoof 첫번째요소, basicSettings의 selectedRoofMaterial에 적용
+ const setRoofPitch = () => {
+ const newAddedRoofs = addedRoofs.map((roof, index) => {
+ if (index === 0) {
+ return { ...roof, pitch: Number(pitchRef.current), angle: getDegreeByChon(pitchRef.current) }
+ } else {
+ return { ...roof }
+ }
+ })
+
+ const newBasicSetting = { ...basicSetting, selectedRoofMaterial: { ...newAddedRoofs[0] } }
+
+ try {
+ basicSettingSave(newAddedRoofs)
+
+ setBasicSetting(newBasicSetting)
+ setAddedRoofs(newAddedRoofs)
+ } catch (error) {
+ swalFire({ text: error.message, icon: 'error' })
+ }
+ }
+
+ /**
+ * 지붕면 할당 저장
+ */
+ const basicSettingSave = async (newAddedRoofs) => {
+ try {
+ const patternData = {
+ objectNo: correntObjectNo,
+ planNo: Number(basicSetting.planNo),
+ roofSizeSet: Number(basicSetting.roofSizeSet),
+ roofAngleSet: basicSetting.roofAngleSet,
+ roofAllocationList: newAddedRoofs.map((item, index) => ({
+ planNo: Number(basicSetting.planNo),
+ roofApply: item.selected,
+ roofSeq: index,
+ roofMatlCd: item.roofMatlCd === null || item.roofMatlCd === undefined ? 'ROOF_ID_WA_53A' : item.roofMatlCd,
+ roofWidth: item.width === null || item.width === undefined ? 0 : Number(item.width),
+ roofHeight: item.length === null || item.length === undefined ? 0 : Number(item.length),
+ roofHajebichi: item.hajebichi === null || item.hajebichi === undefined ? 0 : Number(item.hajebichi),
+ roofGap: !item.raft ? item.raftBaseCd : item.raft,
+ roofLayout: item.layout === null || item.layout === undefined ? 'P' : item.layout,
+ roofPitch: item.pitch === null || item.pitch === undefined ? 4 : Number(item.pitch),
+ roofAngle: item.angle === null || item.angle === undefined ? 21.8 : Number(item.angle),
+ })),
+ }
+
+ await post({ url: `/api/canvas-management/roof-allocation-settings`, data: patternData })
+
+ //Recoil 설정
+ //setCanvasSetting({ ...basicSetting })
+ } catch (error) {
+ swalFire({ text: error.message, icon: 'error' })
+ }
+ }
+
// 동, 서 선택 시 가로라인을 케라바로 설정
const setWestAndEastRoof = (line) => {
if (line.direction === 'left' || line.direction === 'right') {
@@ -644,32 +721,36 @@ export function useRoofShapeSetting(id) {
const index = lines.findIndex((line) => line.idx === selectedLine.idx)
const nextLine = lines[index + 1] || lines[0]
+ history.current.push(selectedLine)
if (nextLine.attributes?.isFixed) {
canvas.discardActiveObject()
return
}
- history.current.push(selectedLine)
+
canvas.setActiveObject(nextLine)
}
// 변별로 설정 내 일변 전으로 돌아가기
const handleRollBack = () => {
if (history.current.length === 0) {
+ canvas.discardActiveObject()
return
}
const lastLine = history.current.pop()
+ canvas.setActiveObject(lastLine)
- currentObject.set({
+ currentObject?.set({
stroke: '#000000',
strokeWidth: 4,
+ attributes: { isFixed: false },
})
lastLine.set({
stroke: '#000000',
strokeWidth: 4,
+ attributes: { isFixed: false },
})
- canvas.setActiveObject(lastLine)
canvas.renderAll()
}
diff --git a/src/hooks/roofcover/useWallLineOffsetSetting.js b/src/hooks/roofcover/useWallLineOffsetSetting.js
index 548b509c..a69a4a19 100644
--- a/src/hooks/roofcover/useWallLineOffsetSetting.js
+++ b/src/hooks/roofcover/useWallLineOffsetSetting.js
@@ -196,7 +196,7 @@ export function useWallLineOffsetSetting(id) {
const handleSave = () => {
if (currentWallLineRef.current === null) {
- alert('보조선을 먼저 선택하세요')
+ // alert('보조선을 먼저 선택하세요')
return
}
switch (type) {
diff --git a/src/hooks/surface/usePlacementShapeDrawing.js b/src/hooks/surface/usePlacementShapeDrawing.js
index dee54673..b1e92f90 100644
--- a/src/hooks/surface/usePlacementShapeDrawing.js
+++ b/src/hooks/surface/usePlacementShapeDrawing.js
@@ -3,6 +3,7 @@ import {
adsorptionPointAddModeState,
adsorptionPointModeState,
adsorptionRangeState,
+ canvasSettingState,
canvasState,
dotLineIntervalSelector,
globalPitchState,
@@ -34,8 +35,9 @@ import { usePopup } from '@/hooks/usePopup'
import { roofDisplaySelector } from '@/store/settingAtom'
import { useRoofFn } from '@/hooks/common/useRoofFn'
+import PlacementSurfaceLineProperty from '@/components/floor-plan/modal/placementShape/PlacementSurfaceLineProperty'
-// 면형상 배치
+// 배치면 그리기
export function usePlacementShapeDrawing(id) {
const canvas = useRecoilValue(canvasState)
const roofDisplay = useRecoilValue(roofDisplaySelector)
@@ -48,7 +50,7 @@ export function usePlacementShapeDrawing(id) {
const { addPolygonByLines, drawDirectionArrow } = usePolygon()
const { tempGridMode } = useTempGrid()
const { setSurfaceShapePattern } = useRoofFn()
-
+ const canvasSetting = useRecoilValue(canvasSettingState)
const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState)
const adsorptionPointAddMode = useRecoilValue(adsorptionPointAddModeState)
const adsorptionPointMode = useRecoilValue(adsorptionPointModeState)
@@ -76,7 +78,7 @@ export function usePlacementShapeDrawing(id) {
const isFix = useRef(false)
- const { closePopup } = usePopup()
+ const { closePopup, addPopup } = usePopup()
const globalPitch = useRecoilValue(globalPitchState)
@@ -91,6 +93,12 @@ export function usePlacementShapeDrawing(id) {
useEffect(() => {
setPoints([])
+
+ return () => {
+ const placementShapeDrawingStartPoint = canvas.getObjects().find((obj) => obj.name === 'placementShapeDrawingStartPoint')
+
+ canvas.remove(placementShapeDrawingStartPoint)
+ }
}, [])
useEffect(() => {
@@ -244,7 +252,12 @@ export function usePlacementShapeDrawing(id) {
setPoints([])
canvas?.renderAll()
- closePopup(id)
+
+ if (+canvasSetting?.roofSizeSet === 3) {
+ closePopup(id)
+ return
+ }
+ addPopup(id, 1,
, false)
}
if (points.length < 3) {
@@ -551,7 +564,7 @@ export function usePlacementShapeDrawing(id) {
const length1Value = length1Ref.current.value
if (diagonalLength <= length1Value) {
- alert('대각선 길이는 직선 길이보다 길어야 합니다.')
+ // alert('대각선 길이는 직선 길이보다 길어야 합니다.')
return
}
@@ -675,8 +688,9 @@ export function usePlacementShapeDrawing(id) {
}
// 포커스가 length1에 있지 않으면 length1에 포커스를 줌
const activeElem = document.activeElement
+
if (activeElem !== length1Ref.current) {
- length1Ref.current.focus()
+ length1Ref.current?.focus()
}
const key = e.key
@@ -685,7 +699,7 @@ export function usePlacementShapeDrawing(id) {
return
}
- const lengthNum = Number(length1Ref.current.value) / 10
+ const lengthNum = Number(length1Ref.current?.value) / 10
if (lengthNum === 0) {
return
}
@@ -872,7 +886,7 @@ export function usePlacementShapeDrawing(id) {
})
if (isAllRightAngle) {
- alert('부정확한 다각형입니다.')
+ // alert('부정확한 다각형입니다.')
return
}
diff --git a/src/hooks/surface/useRoofLinePropertySetting.js b/src/hooks/surface/useRoofLinePropertySetting.js
new file mode 100644
index 00000000..6115f76e
--- /dev/null
+++ b/src/hooks/surface/useRoofLinePropertySetting.js
@@ -0,0 +1,235 @@
+import { LINE_TYPE } from '@/common/common'
+import { canvasState, currentObjectState } from '@/store/canvasAtom'
+import { useEffect, useRef } from 'react'
+import { useRecoilValue } from 'recoil'
+import { usePopup } from '../usePopup'
+import useSWR from 'swr'
+import { useSwal } from '../useSwal'
+import { useMessage } from '../useMessage'
+
+const LINE_COLOR = {
+ EAVES: '#45CD7D',
+ GABLE: '#3FBAE6',
+ RIDGE: '#9e9e9e',
+ DEFAULT: '#000000',
+ ACTIVE: '#EA10AC',
+}
+
+export function useRoofLinePropertySetting(props) {
+ const { id, roof, setIsHidden } = props
+ const canvas = useRecoilValue(canvasState)
+ const currentObject = useRecoilValue(currentObjectState)
+ const history = useRef([])
+ const { closePopup } = usePopup()
+ const { swalFire } = useSwal()
+ const { getMessage } = useMessage()
+
+ useEffect(() => {
+ if (currentObject && currentObject.name === 'cloneRoofLine') {
+ // roof.lines.forEach((line) => {
+ canvas
+ .getObjects()
+ .filter((obj) => obj.name === 'cloneRoofLine')
+ .forEach((line) => {
+ const lineType = line.attributes?.type
+ if (!lineType) {
+ line.set({
+ stroke: '#000000',
+ strokeWidth: 4,
+ })
+ }
+ })
+ currentObject.set({
+ stroke: LINE_COLOR.ACTIVE,
+ strokeWidth: 4,
+ })
+ canvas.renderAll()
+ }
+ }, [currentObject])
+
+ useEffect(() => {
+ return () => {
+ canvas.remove(...canvas.getObjects().filter((obj) => obj.name === 'cloneRoofLine'))
+ canvas.renderAll()
+ }
+ }, [])
+
+ const roofLinesInit = () => {
+ roof.lines.forEach((line) => {
+ line.clone((cloned) => {
+ cloned.set({
+ ...line,
+ stroke: line.attributes?.type ? LINE_COLOR[line.attributes.type.toUpperCase()] : LINE_COLOR.DEFAULT,
+ strokeWidth: 4,
+ visible: true,
+ name: 'cloneRoofLine',
+ selectable: true,
+ originLine: line.id,
+ })
+ line.set({
+ visible: false,
+ attributes: {
+ ...line.attributes,
+ },
+ })
+ canvas.add(cloned)
+ cloned.bringToFront()
+ })
+ // line.set({
+ // stroke: line.attributes?.type ? LINE_COLOR[line.attributes.type.toUpperCase()] : LINE_COLOR.DEFAULT,
+ // strokeWidth: 4,
+ // visible: true,
+ // name: 'roofLine',
+ // })
+ // line.bringToFront()
+ })
+ canvas.renderAll()
+ }
+
+ const handleSetEaves = () => {
+ if (!currentObject) return
+ currentObject.set({
+ attributes: {
+ ...currentObject.attributes,
+ type: LINE_TYPE.WALLLINE.EAVES,
+ },
+ stroke: LINE_COLOR.EAVES,
+ })
+
+ history.current.push(currentObject)
+ nextLineFocus(currentObject)
+ canvas.renderAll()
+ }
+
+ const handleSetGable = () => {
+ if (!currentObject) return
+ currentObject.set({
+ attributes: {
+ ...currentObject.attributes,
+ type: LINE_TYPE.WALLLINE.GABLE,
+ },
+ stroke: LINE_COLOR.GABLE,
+ })
+
+ history.current.push(currentObject)
+ nextLineFocus(currentObject)
+ canvas.renderAll()
+ }
+
+ const handleSetRidge = () => {
+ if (!currentObject) return
+ currentObject.set({
+ attributes: {
+ ...currentObject.attributes,
+ type: LINE_TYPE.SUBLINE.RIDGE,
+ },
+ stroke: LINE_COLOR.RIDGE,
+ })
+
+ history.current.push(currentObject)
+ nextLineFocus(currentObject)
+ canvas.renderAll()
+ }
+
+ const handleRollback = () => {
+ if (history.current.length === 0) {
+ return
+ }
+ const lastLine = history.current.pop()
+
+ delete lastLine.attributes
+
+ lastLine.set({
+ stroke: LINE_COLOR.DEFAULT,
+ strokeWidth: 4,
+ })
+
+ canvas.setActiveObject(lastLine)
+ canvas.renderAll()
+ }
+
+ const handleFix = () => {
+ // const roof = canvas.getObjects().find((obj) => currentObject.parentId === obj.id)
+ // const notSettingLines = roof.lines.filter(
+ const notSettingLines = canvas
+ .getObjects()
+ .filter((obj) => obj.name === 'cloneRoofLine')
+ .filter(
+ (line) =>
+ !line.attributes.type || ![LINE_TYPE.WALLLINE.EAVES, LINE_TYPE.WALLLINE.GABLE, LINE_TYPE.SUBLINE.RIDGE].includes(line.attributes.type),
+ )
+ if (notSettingLines.length > 0) {
+ swalFire({ text: getMessage('modal.canvas.setting.roofline.properties.setting.not.setting'), type: 'alert', icon: 'warning' })
+ return
+ }
+
+ canvas
+ .getObjects()
+ .filter((obj) => obj.name === 'cloneRoofLine')
+ .forEach((line) => {
+ const originLine = roof.lines.find((obj) => obj.id === line.originLine)
+
+ originLine.set({
+ attributes: {
+ ...originLine.attributes,
+ type: line.attributes.type,
+ },
+ visible: true,
+ })
+ canvas.remove(line)
+ })
+
+ // roof.lines.forEach((line) => {
+ // line.set({
+ // stroke: LINE_COLOR.DEFAULT,
+ // strokeWidth: 4,
+ // visible: false,
+ // })
+ // })
+
+ canvas.renderAll()
+ closePopup(id)
+ if (setIsHidden) setIsHidden(false)
+ }
+
+ const nextLineFocus = (selectedLine) => {
+ // const roof = canvas.getObjects().find((obj) => currentObject.parentId === obj.id)
+ // const lines = roof?.lines
+ const lines = canvas.getObjects().filter((obj) => obj.name === 'cloneRoofLine')
+
+ if (!lines) return
+ const index = lines.findIndex((line) => line === selectedLine)
+
+ const nextLine = lines[index + 1] || lines[0]
+ if (nextLine.attributes?.type === 'default') {
+ canvas.setActiveObject(nextLine)
+ } else {
+ //activeObject 해제
+ canvas.discardActiveObject()
+ }
+ }
+
+ const handleClosed = () => {
+ canvas
+ .getObjects()
+ .filter((obj) => obj.name === 'cloneRoofLine')
+ .forEach((line) => {
+ roof.lines
+ .find((obj) => obj.id === line.originLine)
+ .set({
+ visible: true,
+ })
+ canvas.remove(line)
+ })
+ }
+
+ return {
+ roofLinesInit,
+ handleSetEaves,
+ handleSetGable,
+ handleSetRidge,
+ handleRollback,
+ handleFix,
+ handleClosed,
+ }
+}
diff --git a/src/hooks/surface/useSurfaceShapeBatch.js b/src/hooks/surface/useSurfaceShapeBatch.js
index 6397812b..1b0597b6 100644
--- a/src/hooks/surface/useSurfaceShapeBatch.js
+++ b/src/hooks/surface/useSurfaceShapeBatch.js
@@ -2,9 +2,9 @@
import { useEffect } from 'react'
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
-import { canvasState, globalPitchState } from '@/store/canvasAtom'
+import { canvasSettingState, canvasState, currentCanvasPlanState, globalPitchState } from '@/store/canvasAtom'
import { MENU, POLYGON_TYPE } from '@/common/common'
-import { getIntersectionPoint } from '@/util/canvas-util'
+import { getIntersectionPoint, toFixedWithoutRounding } from '@/util/canvas-util'
import { degreesToRadians } from '@turf/turf'
import { QPolygon } from '@/components/fabric/QPolygon'
import { useSwal } from '@/hooks/useSwal'
@@ -19,14 +19,18 @@ import { QLine } from '@/components/fabric/QLine'
import { useRoofFn } from '@/hooks/common/useRoofFn'
import { outerLinePointsState } from '@/store/outerLineAtom'
import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom'
+import { getBackGroundImage } from '@/lib/imageActions'
+import PlacementSurfaceLineProperty from '@/components/floor-plan/modal/placementShape/PlacementSurfaceLineProperty'
+import { v4 as uuidv4 } from 'uuid'
+import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
const { getMessage } = useMessage()
- const { drawDirectionArrow } = usePolygon()
+ const { drawDirectionArrow, addPolygon } = usePolygon()
const lengthTextFont = useRecoilValue(fontSelector('lengthText'))
const resetOuterLinePoints = useResetRecoilState(outerLinePointsState)
const resetPlacementShapeDrawingPoints = useResetRecoilState(placementShapeDrawingPointsState)
-
+ const canvasSetting = useRecoilValue(canvasSettingState)
const canvas = useRecoilValue(canvasState)
const globalPitch = useRecoilValue(globalPitchState)
const roofDisplay = useRecoilValue(roofDisplaySelector)
@@ -34,8 +38,10 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
const { swalFire } = useSwal()
const { addCanvasMouseEventListener, initEvent } = useEvent()
// const { addCanvasMouseEventListener, initEvent } = useContext(EventContext)
- const { closePopup } = usePopup()
+ const { addPopup, closePopup } = usePopup()
const { setSurfaceShapePattern } = useRoofFn()
+ const currentCanvasPlan = useRecoilValue(currentCanvasPlanState)
+ const { fetchSettings } = useCanvasSetting(false)
const applySurfaceShape = (surfaceRefs, selectedType, id) => {
let length1, length2, length3, length4, length5
@@ -66,11 +72,15 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
length5 = surfaceRefs.length5.current.value
}
- length1 = parseInt(length1 === undefined ? 0 : length1 / 10)
- length2 = parseInt(length2 === undefined ? 0 : length2 / 10)
- length3 = parseInt(length3 === undefined ? 0 : length3 / 10)
- length4 = parseInt(length4 === undefined ? 0 : length4 / 10)
- length5 = parseInt(length5 === undefined ? 0 : length5 / 10)
+ console.log(' before length : ', length1, length2, length3, length4, length5)
+
+ length1 = parseFloat(length1 === undefined ? 0 : Number(length1 / 10).toFixed(1))
+ length2 = parseFloat(length2 === undefined ? 0 : Number(length2 / 10).toFixed(1))
+ length3 = parseFloat(length3 === undefined ? 0 : Number(length3 / 10).toFixed(1))
+ length4 = parseFloat(length4 === undefined ? 0 : Number(length4 / 10).toFixed(1))
+ length5 = parseFloat(length5 === undefined ? 0 : Number(length5 / 10).toFixed(1))
+
+ console.log(' after length : ', length1, length2, length3, length4, length5)
let isDrawing = true
let obj = null
@@ -87,10 +97,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH_TEMP))
points = getSurfaceShape(surfaceId, pointer, { length1, length2, length3, length4, length5 })
- console.log('surfaceRefs.xInversion', surfaceRefs.xInversion)
- console.log('surfaceRefs.yInversion', surfaceRefs.yInversion)
- console.log('surfaceRefs.rotate', surfaceRefs.rotate)
-
+ const { xInversion, yInversion, rotate } = surfaceRefs
const options = {
fill: 'transparent',
stroke: 'black',
@@ -104,15 +111,44 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
lockScalingX: true, // X 축 크기 조정 잠금
lockScalingY: true, // Y 축 크기 조정 잠금
name: MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH_TEMP,
- flipX: surfaceRefs.yInversion,
- flipY: surfaceRefs.xInversion,
- angle: Math.abs(surfaceRefs.rotate),
+ flipX: xInversion !== yInversion,
+ // angle: xInversion && yInversion ? Math.abs((rotate + 180) % 360) : Math.abs(rotate),
+ // angle: rotate,
originX: 'center',
originY: 'center',
pitch: globalPitch,
}
obj = new QPolygon(points, options)
+ let imageRotate = 0
+ if (xInversion && !yInversion) {
+ if (rotate % 180 === 0 || rotate < 0) {
+ imageRotate = Math.abs(rotate % 360)
+ } else {
+ if (rotate < 0) {
+ imageRotate = Math.abs((rotate - 180) % 360)
+ } else {
+ imageRotate = Math.abs((rotate + 180) % 360)
+ }
+ }
+ } else if (xInversion && yInversion) {
+ imageRotate = Math.abs((rotate + 360) % 360)
+ } else if (xInversion !== yInversion && rotate < 0) {
+ imageRotate = Math.abs(rotate)
+ } else if (!xInversion && yInversion) {
+ if (rotate % 180 === 0 || rotate < 0) {
+ imageRotate = Math.abs(rotate % 360)
+ } else {
+ if (rotate < 0) {
+ imageRotate = Math.abs((rotate - 180) % 360)
+ } else {
+ imageRotate = Math.abs((rotate + 180) % 360)
+ }
+ }
+ } else {
+ imageRotate = (rotate + 360) % 360
+ }
+ obj.set({ angle: imageRotate })
obj.setCoords() //좌표 변경 적용
canvas?.add(obj)
@@ -142,10 +178,10 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
}
//회전, flip등이 먹은 기준으로 새로생성
- const batchSurface = new QPolygon(obj.getCurrentPoints(), {
+ const batchSurface = addPolygon(obj.getCurrentPoints(), {
fill: 'transparent',
stroke: 'red',
- strokeWidth: 1,
+ strokeWidth: 3,
strokeDasharray: [10, 4],
fontSize: 12,
selectable: true,
@@ -161,14 +197,17 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
surfaceId: surfaceId,
direction: direction,
})
- canvas?.add(batchSurface)
+ canvas.setActiveObject(batchSurface)
setSurfaceShapePattern(batchSurface, roofDisplay.column)
drawDirectionArrow(batchSurface)
- if (setIsHidden) setIsHidden(false)
+ // if (setIsHidden) setIsHidden(false)
// closePopup(id)
initEvent()
+ if (+canvasSetting?.roofSizeSet === 3) return
+ const popupId = uuidv4()
+ addPopup(popupId, 2, )
})
} else {
if (setIsHidden) setIsHidden(false)
@@ -201,7 +240,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
check = false
}
- if (surfaceId === 3 && length3 > length1) {
+ if (surfaceId === 3 && length3 >= length1) {
swalFire({ text: getMessage('surface.shape.validate.size.1to3'), icon: 'error' })
check = false
}
@@ -249,7 +288,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
}
if (length4 >= length3) {
- swalFire({ text: getMessage('surface.shape.validate.size.1to2'), icon: 'error' })
+ swalFire({ text: getMessage('surface.shape.validate.size.3to4'), icon: 'error' })
check = false
}
}
@@ -688,14 +727,47 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
return points
}
- const deleteAllSurfacesAndObjects = () => {
+ const deleteAllSurfacesAndObjects = async () => {
+ const backgroundImage = await getBackGroundImage({
+ objectId: currentCanvasPlan.id,
+ planNo: currentCanvasPlan.planNo,
+ })
+ console.log('🚀 ~ deleteAllSurfacesAndObjects ~ backgroundImage:', backgroundImage)
+
swalFire({
text: getMessage('batch.canvas.delete.all'),
type: 'confirm',
confirmFn: () => {
canvas.clear()
+
+ if (backgroundImage) {
+ fabric.Image.fromURL(`${backgroundImage.path}`, function (img) {
+ console.log('🚀 ~ img:', img)
+ img.set({
+ left: 0,
+ top: 0,
+ width: img.width,
+ height: img.height,
+ name: 'backGroundImage',
+ selectable: false,
+ hasRotatingPoint: false, // 회전 핸들 활성화
+ lockMovementX: false,
+ lockMovementY: false,
+ lockRotation: false,
+ lockScalingX: false,
+ lockScalingY: false,
+ })
+ // image = img
+ canvas?.add(img)
+ canvas?.sendToBack(img)
+ canvas?.renderAll()
+ // setBackImg(img)
+ })
+ }
+
resetOuterLinePoints()
resetPlacementShapeDrawingPoints()
+ fetchSettings()
swalFire({ text: getMessage('plan.message.delete') })
},
// denyFn: () => {
@@ -836,6 +908,8 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
}
const resizeSurfaceShapeBatch = (side, target, width, height) => {
+ const originTarget = { ...target }
+
const objectWidth = target.width
const objectHeight = target.height
const changeWidth = width / 10 / objectWidth
@@ -873,25 +947,27 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
target.set({
scaleX: 1,
scaleY: 1,
- width: parseInt((width / 10).toFixed(0)),
- height: parseInt((height / 10).toFixed(0)),
+ width: toFixedWithoutRounding(width / 10, 1),
+ height: toFixedWithoutRounding(height / 10, 1),
})
//크기 변경후 좌표를 재 적용
- const changedCoords = target.getPointByOrigin('center', 'center')
+ const changedCoords = target.getPointByOrigin(originTarget.originX, originTarget.originY)
target.set({
- originX: 'center',
- originY: 'center',
+ originX: originTarget.originX,
+ originY: originTarget.originY,
left: changedCoords.x,
top: changedCoords.y,
})
+ canvas.renderAll()
//면형상 리사이즈시에만
target.fire('polygonMoved')
target.points = currentPoints
target.fire('modified')
- setSurfaceShapePattern(target, roofDisplay.column)
+ setSurfaceShapePattern(target, roofDisplay.column, false, target.roofMaterial, true)
+
if (target.direction) {
drawDirectionArrow(target)
}
@@ -1036,7 +1112,6 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
deleteAllSurfacesAndObjects,
moveSurfaceShapeBatch,
resizeSurfaceShapeBatch,
-
changeSurfaceLinePropertyEvent,
changeSurfaceLineProperty,
changeSurfaceLinePropertyReset,
diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js
index 8dec3cc0..f1451bd1 100644
--- a/src/hooks/useCanvas.js
+++ b/src/hooks/useCanvas.js
@@ -3,8 +3,8 @@ import { fabric } from 'fabric'
import { actionHandler, anchorWrapper, polygonPositionHandler } from '@/util/canvas-util'
-import { useRecoilState } from 'recoil'
-import { canvasSizeState, canvasState, fontSizeState } from '@/store/canvasAtom'
+import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
+import { canvasSizeState, canvasState, canvasZoomState, fontSizeState } from '@/store/canvasAtom'
import { QLine } from '@/components/fabric/QLine'
import { QPolygon } from '@/components/fabric/QPolygon'
import { defineQLine } from '@/util/qline-utils'
@@ -15,6 +15,7 @@ import { useAxios } from '@/hooks/useAxios'
import { useFont } from '@/hooks/common/useFont'
import { OBJECT_PROTOTYPE, POLYGON_TYPE, RELOAD_TYPE_PROTOTYPE, SAVE_KEY } from '@/common/common'
import { usePlan } from './usePlan'
+import { imageDisplaySelector } from '@/store/settingAtom'
export function useCanvas(id) {
const [canvas, setCanvas] = useRecoilState(canvasState)
@@ -24,7 +25,9 @@ export function useCanvas(id) {
const [canvasSize] = useRecoilState(canvasSizeState)
const [fontSize] = useRecoilState(fontSizeState)
const { setCanvasForEvent, attachDefaultEventOnCanvas } = useCanvasEvent()
+ const isImageDisplay = useRecoilValue(imageDisplaySelector)
const {} = useFont()
+ const resetCanvasZoom = useResetRecoilState(canvasZoomState)
/**
* 처음 셋팅
@@ -34,13 +37,14 @@ export function useCanvas(id) {
height: canvasSize.vertical,
width: canvasSize.horizontal,
backgroundColor: 'white',
+ preserveObjectStacking: true,
selection: false,
})
setCanvas(c)
setCanvasForEvent(c)
attachDefaultEventOnCanvas()
-
+ resetCanvasZoom()
return () => {
// c.dispose()
c.clear()
@@ -529,6 +533,7 @@ export function useCanvas(id) {
lockRotation: false,
lockScalingX: false,
lockScalingY: false,
+ visible: isImageDisplay,
})
// image = img
canvas?.add(img)
diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js
index 9076bbc8..ed24387e 100644
--- a/src/hooks/useCanvasEvent.js
+++ b/src/hooks/useCanvasEvent.js
@@ -396,11 +396,20 @@ export function useCanvasEvent() {
}
const handleZoom = (isZoom) => {
+ let zoom
if (isZoom) {
- setCanvasZoom(canvasZoom + 10)
+ zoom = canvasZoom + 10
+ if (zoom > 500) {
+ return
+ }
} else {
- setCanvasZoom(canvasZoom - 10)
+ zoom = canvasZoom - 10
+ if (zoom < 50) {
+ return
+ }
}
+
+ setCanvasZoom(zoom)
}
const handleZoomClear = () => {
diff --git a/src/hooks/useCirCuitTrestle.js b/src/hooks/useCirCuitTrestle.js
index 0d811dfd..027b965a 100644
--- a/src/hooks/useCirCuitTrestle.js
+++ b/src/hooks/useCirCuitTrestle.js
@@ -11,13 +11,12 @@ import {
seriesState,
} from '@/store/circuitTrestleAtom'
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
-import { useContext } from 'react'
-import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
+import { useContext, useEffect } from 'react'
+import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
import { useMessage } from './useMessage'
-import { useCanvasPopupStatusController } from './common/useCanvasPopupStatusController'
import Big from 'big.js'
-export function useCircuitTrestle() {
+export function useCircuitTrestle(executeEffect = false) {
const [makers, setMakers] = useRecoilState(makersState)
const [selectedMaker, setSelectedMaker] = useRecoilState(selectedMakerState)
const [series, setSeries] = useRecoilState(seriesState)
@@ -27,10 +26,14 @@ export function useCircuitTrestle() {
const selectedModules = useRecoilValue(selectedModuleState)
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const canvas = useRecoilValue(canvasState)
- const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2)
- const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState)
const setModuleStatistics = useSetRecoilState(moduleStatisticsState)
+ const resetModuleStatistics = useResetRecoilState(moduleStatisticsState)
const { getMessage } = useMessage()
+
+ useEffect(() => {
+ if (Object.keys(selectedModules).length > 0 && executeEffect) setModuleStatisticsData()
+ }, [selectedModules])
+
const getOptYn = () => {
return {
maxConnYn: pcsCheck.max ? 'Y' : 'N',
@@ -62,7 +65,6 @@ export function useCircuitTrestle() {
// 사용된 모듈아이템 목록
const getUseModuleItemList = () => {
- console.log('🚀 ~ getUseModuleItemList ~ selectedModules:', selectedModules)
return selectedModules?.itemList?.map((m) => {
return {
itemId: m.itemId,
@@ -83,7 +85,7 @@ export function useCircuitTrestle() {
.getObjects()
.filter((o) => o.id === obj.parentId)[0]
.directionText.replace(/[0-9]/g, ''),
- roofSurfaceIncl: canvas.getObjects().filter((o) => o.id === obj.parentId)[0].roofMaterial.pitch,
+ roofSurfaceIncl: +canvas.getObjects().filter((o) => o.id === obj.parentId)[0].roofMaterial.pitch,
moduleList: getModuleList(obj).map((module) => {
return {
itemId: module.moduleInfo.itemId,
@@ -177,11 +179,17 @@ export function useCircuitTrestle() {
canvas.renderAll()
}
- const setPowerConditionerData = () => {}
-
const setModuleStatisticsData = () => {
console.log('selectedModules', selectedModules)
- if (!selectedModules || !selectedModules?.itemList || selectedModules?.itemList?.length === 0) return
+ if (
+ !selectedModules ||
+ !selectedModules?.itemList ||
+ selectedModules?.itemList?.length === 0 ||
+ canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE).length === 0
+ ) {
+ resetModuleStatistics()
+ return
+ }
const tempHeader = [
{ name: getMessage('simulator.table.sub1'), prop: 'name' },
{ name: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.circuit'), prop: 'circuit' },
@@ -289,6 +297,29 @@ export function useCircuitTrestle() {
setModuleStatistics({ header: tempHeader, rows: tempRows.filter((row) => row.wpOut !== 0), footer: tempFooter })
}
+ const resetCircuits = () => {
+ const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
+ const circuitTexts = canvas.getObjects().filter((obj) => obj.name === 'circuitNumber')
+
+ surfaces.forEach((surface) => {
+ surface.modules.forEach((module) => {
+ module.circuit = null
+ module.pcsItemId = null
+ module.circuitNumber = null
+ })
+ surface.isComplete = false
+ })
+ if (circuitTexts.length > 0) canvas.remove(...circuitTexts)
+ canvas.renderAll()
+
+ setModuleStatisticsData()
+ }
+
+ const isExistCircuit = () => {
+ const circuits = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && obj.circuit)
+ return circuits.length > 0
+ }
+
return {
makers,
setMakers,
@@ -310,5 +341,7 @@ export function useCircuitTrestle() {
getModuleList,
removeNotAllocationModules,
setModuleStatisticsData,
+ resetCircuits,
+ isExistCircuit,
}
}
diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js
index fcac9947..8eb4d69e 100644
--- a/src/hooks/useContextMenu.js
+++ b/src/hooks/useContextMenu.js
@@ -1,5 +1,5 @@
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
-import { canvasState, currentMenuState, currentObjectState } from '@/store/canvasAtom'
+import { canvasSettingState, canvasState, currentMenuState, currentObjectState } from '@/store/canvasAtom'
import { useEffect, useState } from 'react'
import { MENU, POLYGON_TYPE } from '@/common/common'
import AuxiliarySize from '@/components/floor-plan/modal/auxiliary/AuxiliarySize'
@@ -41,9 +41,14 @@ import { useGrid } from './common/useGrid'
import { useAdsorptionPoint } from './useAdsorptionPoint'
import { useRoofFn } from '@/hooks/common/useRoofFn'
import { MODULE_ALIGN_TYPE, useModule } from './module/useModule'
+import PlacementSurfaceLineProperty from '@/components/floor-plan/modal/placementShape/PlacementSurfaceLineProperty'
+import { selectedMenuState } from '@/store/menuAtom'
+import { useTrestle } from './module/useTrestle'
+import { useCircuitTrestle } from './useCirCuitTrestle'
export function useContextMenu() {
const canvas = useRecoilValue(canvasState)
+ const canvasSetting = useRecoilValue(canvasSettingState)
const currentMenu = useRecoilValue(currentMenuState) // 현재 메뉴
const setContextPopupPosition = useSetRecoilState(contextPopupPositionState) // 현재 메뉴
const [contextMenu, setContextMenu] = useRecoilState(contextMenuListState) // 메뉴.object 별 context menu
@@ -65,251 +70,16 @@ export function useContextMenu() {
const { removeGrid } = useGrid()
const { removeAdsorptionPoint } = useAdsorptionPoint()
const commonTextFont = useRecoilValue(fontSelector('commonText'))
- const { settingsData, setSettingsDataSave } = useCanvasSetting()
+ const { settingsData, setSettingsDataSave } = useCanvasSetting(false)
const { swalFire } = useSwal()
const { alignModule, modulesRemove, moduleRoofRemove } = useModule()
const { removeRoofMaterial, removeAllRoofMaterial, moveRoofMaterial, removeOuterLines } = useRoofFn()
-
+ const selectedMenu = useRecoilValue(selectedMenuState)
+ const { isAllComplete, clear: resetModule } = useTrestle()
+ const { isExistCircuit } = useCircuitTrestle()
const currentMenuSetting = () => {
- switch (currentMenu) {
- case MENU.PLAN_DRAWING:
- setContextMenu([
- [
- {
- id: 'gridMove',
- name: getMessage('modal.grid.move'),
- component: ,
- },
- {
- id: 'gridCopy',
- name: getMessage('modal.grid.copy'),
- component: ,
- },
- {
- id: 'gridColorEdit',
- name: getMessage('modal.grid.color.edit'),
- component: (
-
- ),
- },
- {
- id: 'remove',
- name: getMessage('delete'),
- },
- {
- id: 'removeAll',
- name: getMessage('delete.all'),
- fn: () => {
- removeGrid()
- removeAdsorptionPoint()
- },
- },
- ],
- ])
- break
- case MENU.ROOF_COVERING.EXTERIOR_WALL_LINE:
- case MENU.ROOF_COVERING.ROOF_SHAPE_SETTINGS:
- case MENU.ROOF_COVERING.ROOF_SHAPE_PASSIVITY_SETTINGS:
- case MENU.ROOF_COVERING.ROOF_SHAPE_EDITING:
- case MENU.ROOF_COVERING.HELP_LINE_DRAWING:
- case MENU.ROOF_COVERING.EAVES_KERAVA_EDIT:
- case MENU.ROOF_COVERING.MOVEMENT_SHAPE_UPDOWN:
- case MENU.ROOF_COVERING.OUTLINE_EDIT_OFFSET:
- case MENU.ROOF_COVERING.ROOF_SHAPE_ALLOC:
- case MENU.ROOF_COVERING.DEFAULT:
- setContextMenu([
- [
- {
- id: 'roofMaterialPlacement',
- name: getMessage('contextmenu.roof.material.placement'),
- component: ,
- },
-
- {
- id: 'roofMaterialRemoveAll',
- name: getMessage('contextmenu.roof.material.remove.all'),
- fn: () => removeAllRoofMaterial(),
- },
- {
- id: 'selectMove',
- name: getMessage('contextmenu.select.move'),
- fn: (currentMousePos) => {
- moveRoofMaterial(currentMousePos)
- },
- },
- {
- id: 'wallLineRemove',
- name: getMessage('contextmenu.wallline.remove'),
- fn: (currentMousePos) => {
- removeOuterLines(currentMousePos)
- },
- },
- ],
- [
- {
- id: 'sizeEdit',
- name: getMessage('contextmenu.size.edit'),
- component: ,
- },
- {
- id: 'auxiliaryMove',
- name: `${getMessage('contextmenu.auxiliary.move')}(M)`,
- shortcut: ['m', 'M'],
- component: ,
- },
- {
- id: 'auxiliaryCopy',
- name: `${getMessage('contextmenu.auxiliary.copy')}(C)`,
- shortcut: ['c', 'C'],
- component: ,
- },
- {
- id: 'auxiliaryRemove',
- shortcut: ['d', 'D'],
- name: `${getMessage('contextmenu.auxiliary.remove')}(D)`,
- fn: () => {
- if (!currentObject) return
- const roof = canvas.getObjects().filter((obj) => obj.id === currentObject.attributes.roofId)[0]
- if (!roof) {
- // 아직 innerLines로 세팅이 안되어있는 line인 경우 제거
- canvas.remove(currentObject)
- canvas.discardActiveObject()
- return
- }
- const innerLines = roof.innerLines?.filter((line) => currentObject.id !== line.id)
- roof.innerLines = [...innerLines]
- canvas.remove(currentObject)
- canvas.discardActiveObject()
- },
- },
- {
- id: 'auxiliaryVerticalBisector',
- name: getMessage('contextmenu.auxiliary.vertical.bisector'),
- fn: () => {
- if (!currentObject) return
- const slope = (currentObject.y2 - currentObject.y1) / (currentObject.x2 - currentObject.x1)
- const length = currentObject.length
-
- let startX, startY, endX, endY
- if (slope === 0) {
- startX = endX = (currentObject.x1 + currentObject.x2) / 2
- startY = currentObject.y2 - length / 2
- endY = currentObject.y2 + length / 2
- } else if (slope === Infinity) {
- startX = currentObject.x1 - length / 2
- startY = endY = (currentObject.y1 + currentObject.y2) / 2
- endX = currentObject.x1 + length / 2
- } else {
- const bisectorSlope = -1 / slope
- const dx = length / 2 / Math.sqrt(1 + bisectorSlope * bisectorSlope)
- const dy = bisectorSlope * dx
-
- startX = (currentObject.x1 + currentObject.x2) / 2 + dx
- startY = (currentObject.y1 + currentObject.y2) / 2 + dy
- endX = (currentObject.x1 + currentObject.x2) / 2 - dx
- endY = (currentObject.y1 + currentObject.y2) / 2 - dy
- }
-
- const line = addLine([startX, startY, endX, endY], {
- stroke: 'red',
- strokeWidth: 1,
- selectable: true,
- name: 'auxiliaryLine',
- attributes: { ...currentObject.attributes },
- })
-
- if (!currentObject.attributes.roofId) {
- return
- }
-
- canvas
- .getObjects()
- .filter((obj) => obj.id === currentObject.attributes.roofId)[0]
- .innerLines.push(line)
- },
- },
- {
- id: 'auxiliaryRemoveAll',
- name: getMessage('contextmenu.auxiliary.remove.all'),
- fn: () => {
- if (!currentObject) {
- swalFire({ text: getMessage('roof.is.not.selected') })
- return
- }
- const innerLines = canvas.getObjects().filter((obj) => obj.id === currentObject.attributes.roofId)[0]?.innerLines
- if (innerLines) {
- innerLines.forEach((line) => {
- canvas.remove(line)
- })
- innerLines.length = 0
- }
-
- // 확정되지 않은 보조선
- const notFixedAuxiliaryLines = canvas.getObjects().filter((obj) => obj.name === 'auxiliaryLine' && !obj.isAuxiliaryFixed)
-
- notFixedAuxiliaryLines.forEach((line) => {
- canvas.remove(line)
- })
-
- canvas.renderAll()
- },
- },
- ],
- ])
- break
- case MENU.BATCH_CANVAS.SLOPE_SETTING:
- case MENU.BATCH_CANVAS.BATCH_DRAWING:
- case MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH:
- case MENU.BATCH_CANVAS.OBJECT_BATCH:
- case MENU.BATCH_CANVAS.ALL_REMOVE:
- case MENU.BATCH_CANVAS.DEFAULT:
- setContextMenu([
- [
- {
- id: 'sizeEdit',
- name: getMessage('contextmenu.size.edit'),
- component: ,
- },
- {
- id: 'remove',
- shortcut: ['d', 'D'],
- name: `${getMessage('contextmenu.remove')}(D)`,
- },
- {
- id: 'move',
- shortcut: ['m', 'M'],
- name: `${getMessage('contextmenu.move')}(M)`,
- },
- {
- id: 'copy',
- shortcut: ['c', 'C'],
- name: `${getMessage('contextmenu.copy')}(C)`,
- },
- ],
- [
- {
- id: 'roofMaterialEdit',
- name: getMessage('contextmenu.roof.material.edit'),
- component: ,
- },
- {
- id: 'linePropertyEdit',
- name: getMessage('contextmenu.line.property.edit'),
- component: ,
- },
- {
- id: 'flowDirectionEdit',
- name: getMessage('contextmenu.flow.direction.edit'),
- component: ,
- },
- ],
- ])
+ switch (selectedMenu) {
+ case 'outline':
break
default:
setContextMenu([])
@@ -358,89 +128,234 @@ export function useContextMenu() {
switch (currentObject.name) {
case 'triangleDormer':
case 'pentagonDormer':
- setContextMenu([
- [
- {
- id: 'sizeEdit',
- name: getMessage('contextmenu.size.edit'),
- component: ,
- },
- {
- id: 'dormerRemove',
- shortcut: ['d', 'D'],
- name: `${getMessage('contextmenu.remove')}(D)`,
- fn: () => deleteObject(),
- },
- {
- id: 'dormerMove',
- shortcut: ['m', 'M'],
- name: `${getMessage('contextmenu.move')}(M)`,
- fn: () => moveObjectBatch(),
- },
- {
- id: 'dormerCopy',
- shortcut: ['c', 'C'],
- name: `${getMessage('contextmenu.copy')}(C)`,
- fn: () => copyObject(),
- },
- {
- id: 'roofMaterialEdit',
- name: getMessage('contextmenu.roof.material.edit'),
- component: ,
- },
- {
- id: 'dormerOffset',
- name: getMessage('contextmenu.dormer.offset'),
- component: ,
- },
- ],
- ])
+ if (selectedMenu === 'surface') {
+ setContextMenu([
+ [
+ {
+ id: 'dormerRemove',
+ shortcut: ['d', 'D'],
+ name: `${getMessage('contextmenu.remove')}(D)`,
+ fn: () => deleteObject(),
+ },
+ {
+ id: 'dormerMove',
+ shortcut: ['m', 'M'],
+ name: `${getMessage('contextmenu.move')}(M)`,
+ fn: () => moveObjectBatch(),
+ },
+ {
+ id: 'dormerCopy',
+ shortcut: ['c', 'C'],
+ name: `${getMessage('contextmenu.copy')}(C)`,
+ fn: () => copyObject(),
+ },
+ {
+ id: 'dormerOffset',
+ name: getMessage('contextmenu.dormer.offset'),
+ component: ,
+ },
+ ],
+ ])
+ }
break
case 'roof':
- setContextMenu([
- [
- {
- id: 'sizeEdit',
- name: getMessage('contextmenu.size.edit'),
- component: ,
- },
- {
- id: 'roofMaterialRemove',
- shortcut: ['d', 'D'],
- name: `${getMessage('contextmenu.remove')}(D)`,
- fn: () => deleteObject(),
- },
- {
- id: 'roofMaterialMove',
- shortcut: ['m', 'M'],
- name: `${getMessage('contextmenu.move')}(M)`,
- fn: () => moveSurfaceShapeBatch(),
- },
- {
- id: 'roofMaterialCopy',
- shortcut: ['c', 'C'],
- name: `${getMessage('contextmenu.copy')}(C)`,
- fn: () => copyObject(),
- },
- ],
- [
- {
- id: 'roofMaterialEdit',
- name: getMessage('contextmenu.roof.material.edit'),
- component: ,
- },
- {
- id: 'linePropertyEdit',
- name: getMessage('contextmenu.line.property.edit'),
- component: ,
- },
- {
- id: 'flowDirectionEdit',
- name: getMessage('contextmenu.flow.direction.edit'),
- component: ,
- },
- ],
- ])
+ case 'auxiliaryLine':
+ case 'hip':
+ case 'ridge':
+ if (selectedMenu === 'surface') {
+ setContextMenu([
+ [
+ {
+ id: 'sizeEdit',
+ name: getMessage('contextmenu.size.edit'),
+ component: ,
+ },
+ {
+ id: 'roofMaterialRemove',
+ shortcut: ['d', 'D'],
+ name: `${getMessage('contextmenu.remove')}(D)`,
+ fn: () => deleteObject(),
+ },
+ {
+ id: 'roofMaterialMove',
+ shortcut: ['m', 'M'],
+ name: `${getMessage('contextmenu.move')}(M)`,
+ fn: () => moveSurfaceShapeBatch(),
+ },
+ {
+ id: 'roofMaterialCopy',
+ shortcut: ['c', 'C'],
+ name: `${getMessage('contextmenu.copy')}(C)`,
+ fn: () => copyObject(),
+ },
+ ],
+ [
+ {
+ id: 'roofMaterialEdit',
+ name: getMessage('contextmenu.roof.material.edit'),
+ component: ,
+ },
+ {
+ id: 'linePropertyEdit',
+ name: getMessage('contextmenu.line.property.edit'),
+ fn: () => {
+ if (+canvasSetting.roofSizeSet === 3) {
+ swalFire({ text: getMessage('contextmenu.line.property.edit.roof.size.3') })
+ } else {
+ addPopup(popupId, 1, )
+ }
+ },
+ // component: ,
+ },
+ {
+ id: 'flowDirectionEdit',
+ name: getMessage('contextmenu.flow.direction.edit'),
+ component: ,
+ },
+ ],
+ ])
+ } else if (selectedMenu === 'outline') {
+ setContextMenu([
+ [
+ {
+ id: 'roofMaterialPlacement',
+ name: getMessage('contextmenu.roof.material.placement'),
+ component: ,
+ },
+
+ {
+ id: 'roofMaterialRemoveAll',
+ name: getMessage('contextmenu.roof.material.remove.all'),
+ fn: () => removeAllRoofMaterial(),
+ },
+ {
+ id: 'selectMove',
+ name: getMessage('contextmenu.select.move'),
+ fn: (currentMousePos) => {
+ moveRoofMaterial(currentMousePos)
+ },
+ },
+ {
+ id: 'wallLineRemove',
+ name: getMessage('contextmenu.wallline.remove'),
+ fn: (currentMousePos) => {
+ removeOuterLines(currentMousePos)
+ },
+ },
+ ],
+ [
+ {
+ id: 'sizeEdit',
+ name: getMessage('contextmenu.size.edit'),
+ component: ,
+ },
+ {
+ id: 'auxiliaryMove',
+ name: `${getMessage('contextmenu.auxiliary.move')}(M)`,
+ shortcut: ['m', 'M'],
+ component: ,
+ },
+ {
+ id: 'auxiliaryCopy',
+ name: `${getMessage('contextmenu.auxiliary.copy')}(C)`,
+ shortcut: ['c', 'C'],
+ component: ,
+ },
+ {
+ id: 'auxiliaryRemove',
+ shortcut: ['d', 'D'],
+ name: `${getMessage('contextmenu.auxiliary.remove')}(D)`,
+ fn: () => {
+ if (!currentObject) return
+ const roof = canvas.getObjects().filter((obj) => obj.id === currentObject.attributes.roofId)[0]
+ if (!roof) {
+ // 아직 innerLines로 세팅이 안되어있는 line인 경우 제거
+ canvas.remove(currentObject)
+ canvas.discardActiveObject()
+ return
+ }
+ const innerLines = roof.innerLines?.filter((line) => currentObject.id !== line.id)
+ roof.innerLines = [...innerLines]
+ canvas.remove(currentObject)
+ canvas.discardActiveObject()
+ },
+ },
+ {
+ id: 'auxiliaryVerticalBisector',
+ name: getMessage('contextmenu.auxiliary.vertical.bisector'),
+ fn: () => {
+ if (!currentObject) return
+ const slope = (currentObject.y2 - currentObject.y1) / (currentObject.x2 - currentObject.x1)
+ const length = currentObject.length
+
+ let startX, startY, endX, endY
+ if (slope === 0) {
+ startX = endX = (currentObject.x1 + currentObject.x2) / 2
+ startY = currentObject.y2 - length / 2
+ endY = currentObject.y2 + length / 2
+ } else if (slope === Infinity) {
+ startX = currentObject.x1 - length / 2
+ startY = endY = (currentObject.y1 + currentObject.y2) / 2
+ endX = currentObject.x1 + length / 2
+ } else {
+ const bisectorSlope = -1 / slope
+ const dx = length / 2 / Math.sqrt(1 + bisectorSlope * bisectorSlope)
+ const dy = bisectorSlope * dx
+
+ startX = (currentObject.x1 + currentObject.x2) / 2 + dx
+ startY = (currentObject.y1 + currentObject.y2) / 2 + dy
+ endX = (currentObject.x1 + currentObject.x2) / 2 - dx
+ endY = (currentObject.y1 + currentObject.y2) / 2 - dy
+ }
+
+ const line = addLine([startX, startY, endX, endY], {
+ stroke: 'red',
+ strokeWidth: 1,
+ selectable: true,
+ name: 'auxiliaryLine',
+ attributes: { ...currentObject.attributes },
+ })
+
+ if (!currentObject.attributes.roofId) {
+ return
+ }
+
+ canvas
+ .getObjects()
+ .filter((obj) => obj.id === currentObject.attributes.roofId)[0]
+ .innerLines.push(line)
+ },
+ },
+ {
+ id: 'auxiliaryRemoveAll',
+ name: getMessage('contextmenu.auxiliary.remove.all'),
+ fn: () => {
+ if (!currentObject) {
+ swalFire({ text: getMessage('roof.is.not.selected') })
+ return
+ }
+ const innerLines = canvas.getObjects().filter((obj) => obj.id === currentObject.attributes.roofId)[0]?.innerLines
+ if (innerLines) {
+ innerLines.forEach((line) => {
+ canvas.remove(line)
+ })
+ innerLines.length = 0
+ }
+
+ // 확정되지 않은 보조선
+ const notFixedAuxiliaryLines = canvas.getObjects().filter((obj) => obj.name === 'auxiliaryLine' && !obj.isAuxiliaryFixed)
+
+ notFixedAuxiliaryLines.forEach((line) => {
+ canvas.remove(line)
+ })
+
+ canvas.renderAll()
+ },
+ },
+ ],
+ ])
+ }
+
break
case 'opening':
setContextMenu([
@@ -685,79 +600,200 @@ export function useContextMenu() {
{
id: 'move',
name: getMessage('contextmenu.move'),
- component: ,
+ fn: () => {
+ if (currentObject.circuit) {
+ swalFire({
+ title: getMessage('can.not.move.module'),
+ icon: 'error',
+ type: 'alert',
+ })
+ return
+ }
+
+ addPopup(popupId, 1, )
+ },
+ // component: ,
},
{
id: 'copy',
name: getMessage('contextmenu.copy'),
- component: ,
+ fn: () => {
+ if (currentObject.circuit) {
+ swalFire({
+ title: getMessage('can.not.copy.module'),
+ icon: 'error',
+ type: 'alert',
+ })
+ return
+ }
+
+ addPopup(popupId, 1, )
+ },
},
],
[
{
id: 'columnMove',
name: getMessage('contextmenu.column.move'),
- component: ,
+ fn: () => {
+ if (isAllComplete()) {
+ swalFire({
+ title: getMessage('can.not.move.module'),
+ icon: 'error',
+ type: 'alert',
+ })
+ return
+ }
+ resetModule()
+ addPopup(popupId, 1, )
+ },
},
{
id: 'columnCopy',
name: getMessage('contextmenu.column.copy'),
- component: ,
+ fn: () => {
+ if (isAllComplete()) {
+ swalFire({
+ title: getMessage('can.not.copy.module'),
+ icon: 'error',
+ type: 'alert',
+ })
+ return
+ }
+ resetModule()
+ addPopup(popupId, 1, )
+ },
+ // component: ,
},
{
id: 'columnRemove',
name: getMessage('contextmenu.column.remove'),
- component: ,
+ fn: () => {
+ if (isExistCircuit()) {
+ resetModule()
+ }
+
+ addPopup(popupId, 1, )
+ },
+ // component: ,
},
{
id: 'columnInsert',
name: getMessage('contextmenu.column.insert'),
- component: ,
+ fn: () => {
+ if (isExistCircuit()) {
+ resetModule()
+ }
+
+ addPopup(popupId, 1, )
+ },
+ // component: ,
},
],
[
{
id: 'rowMove',
name: getMessage('contextmenu.row.move'),
- component: ,
+ fn: () => {
+ if (isAllComplete()) {
+ swalFire({
+ title: getMessage('can.not.move.module'),
+ icon: 'error',
+ type: 'alert',
+ })
+ return
+ }
+ resetModule()
+ addPopup(popupId, 1, )
+ },
+ // component: ,
},
{
id: 'rowCopy',
name: getMessage('contextmenu.row.copy'),
- component: ,
+ fn: () => {
+ if (isAllComplete()) {
+ swalFire({
+ title: getMessage('can.not.copy.module'),
+ icon: 'error',
+ type: 'alert',
+ })
+ return
+ }
+ resetModule()
+ addPopup(popupId, 1, )
+ },
+ // component: ,
},
{
id: 'rowRemove',
name: getMessage('contextmenu.row.remove'),
- component: ,
+ fn: () => {
+ if (isExistCircuit()) {
+ resetModule()
+ }
+
+ addPopup(popupId, 1, )
+ },
+ // component: ,
},
{
id: 'rowInsert',
name: getMessage('contextmenu.row.insert'),
- component: ,
+ fn: () => {
+ if (isExistCircuit()) {
+ resetModule()
+ }
+
+ addPopup(popupId, 1, )
+ },
+ // component: ,
},
],
])
break
case 'moduleSetupSurface':
- case 'roof':
setContextMenu([
[
{
id: 'moduleVerticalCenterAlign',
name: getMessage('contextmenu.module.vertical.align'),
- fn: () => alignModule(MODULE_ALIGN_TYPE.VERTICAL, currentObject.arrayData),
+ fn: () => {
+ if (isAllComplete()) {
+ swalFire({
+ title: getMessage('can.not.move.module'),
+ icon: 'error',
+ type: 'alert',
+ })
+ return
+ }
+
+ resetModule()
+ alignModule(MODULE_ALIGN_TYPE.VERTICAL, currentObject.arrayData ?? [currentObject])
+ },
},
{
id: 'moduleHorizonCenterAlign',
name: getMessage('contextmenu.module.horizon.align'),
- fn: () => alignModule(MODULE_ALIGN_TYPE.HORIZONTAL, currentObject.arrayData),
+ fn: () => {
+ if (isAllComplete()) {
+ swalFire({
+ title: getMessage('can.not.move.module'),
+ icon: 'error',
+ type: 'alert',
+ })
+ return
+ }
+
+ resetModule()
+ alignModule(MODULE_ALIGN_TYPE.HORIZONTAL, currentObject.arrayData ?? [currentObject])
+ },
},
{
id: 'moduleRemove',
name: getMessage('contextmenu.module.remove'),
fn: () => {
- moduleRoofRemove(currentObject.arrayData)
+ moduleRoofRemove(currentObject.arrayData ?? [currentObject])
// const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
// const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE)
@@ -768,12 +804,45 @@ export function useContextMenu() {
{
id: 'moduleMove',
name: getMessage('contextmenu.module.move'),
- component: ,
+ fn: () => {
+ if (isAllComplete()) {
+ swalFire({
+ title: getMessage('can.not.move.module'),
+ icon: 'error',
+ type: 'alert',
+ })
+ return
+ }
+ resetModule()
+ addPopup(
+ popupId,
+ 1,
+ ,
+ )
+ },
+
+ // component: ,
},
{
id: 'moduleCopy',
name: getMessage('contextmenu.module.copy'),
- component: ,
+ fn: () => {
+ if (isAllComplete()) {
+ swalFire({
+ title: getMessage('can.not.move.module'),
+ icon: 'error',
+ type: 'alert',
+ })
+ return
+ }
+ resetModule()
+ addPopup(
+ popupId,
+ 1,
+ ,
+ )
+ },
+ // component: ,
},
// {
// id: 'moduleCircuitNumberEdit',
diff --git a/src/hooks/useEstimate.js b/src/hooks/useEstimate.js
index 5192ec0c..fae0b558 100644
--- a/src/hooks/useEstimate.js
+++ b/src/hooks/useEstimate.js
@@ -9,6 +9,8 @@ import { GlobalDataContext } from '@/app/GlobalDataProvider'
import { QcastContext } from '@/app/QcastProvider'
import { currentCanvasPlanState } from '@/store/canvasAtom'
import { loginUserStore } from '@/store/commonAtom'
+import { useTrestle } from '@/hooks/module/useTrestle'
+import { usePlan } from '@/hooks/usePlan'
export function useEstimate() {
const { managementStateLoaded } = useContext(GlobalDataContext)
@@ -20,13 +22,15 @@ export function useEstimate() {
const { promisePost } = useAxios()
const { swalFire } = useSwal()
+ const { setAllModuleSurfaceIsComplete } = useTrestle()
+ const { saveCanvas } = usePlan()
+
/**
* 도면 견적서 저장
+ *
+ * @param {Object} estimateParam - 견적서 저장 데이터
*/
const saveEstimate = async (estimateParam) => {
- // 로딩 임시 주석
- // setIsGlobalLoading(true)
-
const userId = loginUserState.userId
const saleStoreId = managementStateLoaded.saleStoreId
const objectNo = currentCanvasPlan.objectNo
@@ -56,8 +60,14 @@ export function useEstimate() {
await promisePost({ url: '/api/estimate/save-estimate', data: saveEstimateData })
.then(async () => {
- // 견적서 저장이 완료되면 견적서 페이지로 이동
- moveEstimate(planNo, objectNo)
+ setAllModuleSurfaceIsComplete(true)
+
+ // 캔버스 저장
+ await saveCanvas(false)
+ setIsGlobalLoading(false)
+
+ /* 견적서 저장이 완료되면 견적서 페이지로 이동 */
+ // moveEstimate(planNo, objectNo)
})
.catch((error) => {
setIsGlobalLoading(false)
@@ -67,6 +77,9 @@ export function useEstimate() {
/**
* 견적서 페이지로 이동
+ *
+ * @param {string} planNo - 플랜번호
+ * @param {string} objectNo - 물건번호
*/
const moveEstimate = (planNo, objectNo) => {
router.push(`/floor-plan/estimate/5?pid=${planNo}&objectNo=${objectNo}`)
diff --git a/src/hooks/useEvent.js b/src/hooks/useEvent.js
index 55058cf4..d3d270f6 100644
--- a/src/hooks/useEvent.js
+++ b/src/hooks/useEvent.js
@@ -2,7 +2,7 @@ import { useRef } from 'react'
import { useRecoilValue, useSetRecoilState } from 'recoil'
import { canvasState, canvasZoomState, currentMenuState, textModeState } from '@/store/canvasAtom'
import { fabric } from 'fabric'
-import { calculateDistance, calculateIntersection, distanceBetweenPoints, findClosestPoint } from '@/util/canvas-util'
+import { calculateDistance, calculateDistancePoint, calculateIntersection, distanceBetweenPoints, findClosestPoint } from '@/util/canvas-util'
import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint'
import { useDotLineGrid } from '@/hooks/useDotLineGrid'
import { useTempGrid } from '@/hooks/useTempGrid'
@@ -101,10 +101,31 @@ export function useEvent() {
if (dotLineGridSetting.LINE || canvas.getObjects().filter((obj) => ['lineGrid', 'tempGrid'].includes(obj.name)).length > 0) {
const closestLine = getClosestLineGrid(pointer)
- if (closestLine) {
- const distance = calculateDistance(pointer, closestLine)
+ const horizonLines = canvas.getObjects().filter((obj) => obj.name === 'lineGrid' && obj.direction === 'horizontal')
+ const verticalLines = canvas.getObjects().filter((obj) => obj.name === 'lineGrid' && obj.direction === 'vertical')
- if (distance < adsorptionRange) {
+ const closestHorizontalLine = horizonLines.reduce((prev, curr) => {
+ const prevDistance = calculateDistance(pointer, prev)
+ const currDistance = calculateDistance(pointer, curr)
+ return prevDistance < currDistance ? prev : curr
+ })
+
+ const closestVerticalLine = verticalLines.reduce((prev, curr) => {
+ const prevDistance = calculateDistance(pointer, prev)
+ const currDistance = calculateDistance(pointer, curr)
+ return prevDistance < currDistance ? prev : curr
+ })
+
+ const closestIntersectionPoint = calculateIntersection(closestHorizontalLine, closestVerticalLine)
+
+ if (closestLine) {
+ const distanceClosestLine = calculateDistance(pointer, closestLine)
+ let distanceClosestPoint = Infinity
+ if (closestIntersectionPoint) {
+ distanceClosestPoint = calculateDistancePoint(pointer, closestIntersectionPoint)
+ }
+
+ if (distanceClosestLine < adsorptionRange) {
arrivalPoint =
closestLine.direction === 'vertical'
? { x: closestLine.x1, y: pointer.y }
@@ -112,6 +133,10 @@ export function useEvent() {
x: pointer.x,
y: closestLine.y1,
}
+
+ if (distanceClosestPoint * 2 < adsorptionRange) {
+ arrivalPoint = { ...closestIntersectionPoint }
+ }
}
}
}
@@ -174,7 +199,7 @@ export function useEvent() {
}
} catch (e) {}
- const horizontalLine = new fabric.Line([-1 * canvas.width, arrivalPoint.y, 2 * canvas.width, arrivalPoint.y], {
+ const horizontalLine = new fabric.Line([-4 * canvas.width, arrivalPoint.y, 4 * canvas.width, arrivalPoint.y], {
stroke: 'red',
strokeWidth: 1,
selectable: false,
@@ -182,7 +207,7 @@ export function useEvent() {
})
// 세로선
- const verticalLine = new fabric.Line([arrivalPoint.x, -1 * canvas.height, arrivalPoint.x, 2 * canvas.height], {
+ const verticalLine = new fabric.Line([arrivalPoint.x, -4 * canvas.height, arrivalPoint.x, 4 * canvas.height], {
stroke: 'red',
strokeWidth: 1,
selectable: false,
diff --git a/src/hooks/useLine.js b/src/hooks/useLine.js
index e2667e80..b447d4f0 100644
--- a/src/hooks/useLine.js
+++ b/src/hooks/useLine.js
@@ -40,7 +40,7 @@ export const useLine = () => {
})
canvas
?.getObjects()
- .find((obj) => obj.parent === line)
+ .find((obj) => obj.parentId === line.id)
.set({
visible: false,
})
@@ -53,7 +53,7 @@ export const useLine = () => {
})
canvas
?.getObjects()
- .find((obj) => obj.parent === line)
+ .find((obj) => obj.parentId === line.id)
.set({
visible: true,
})
diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js
index 4dcbd6b7..e4beea37 100644
--- a/src/hooks/useMode.js
+++ b/src/hooks/useMode.js
@@ -5803,5 +5803,8 @@ export function useMode() {
drawCellManualInTrestle,
setDirectionTrestles,
cutHelpLines,
+ createRoofPolygon,
+ createMarginPolygon,
+ createPaddingPolygon,
}
}
diff --git a/src/hooks/usePagination.js b/src/hooks/usePagination.js
index c0a9ea50..99ba4d8a 100644
--- a/src/hooks/usePagination.js
+++ b/src/hooks/usePagination.js
@@ -23,11 +23,13 @@ const usePagination = ({ pageNo = 1, pageSize = 10, pagePerBlock = 10, totalCoun
const pages = Array.from({ length: totalPages }, (_, i) => i + 1)
const startPage = Math.max(1, (pageGroup - 1) * pagePerBlock + 1)
const endPage = Math.min(totalPages, pageGroup * pagePerBlock)
- const pageRange = Array.from({ length: endPage !== totalPages ? pagePerBlock : endPage - startPage + 1 }, (_, i) => {
+ let pageRange = Array.from({ length: endPage !== totalPages ? pagePerBlock : endPage - startPage + 1 }, (_, i) => {
if (i + startPage > endPage) return
return i + startPage
})
+ //검색결과 없을때 [1]로 초기화
+ pageRange = pageRange.length === 0 ? [1] : pageRange
// console.log('pageRange', pageRange)
// console.log('startPage', startPage)
// console.log('endPage', endPage)
diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js
index 440a6319..013e00c4 100644
--- a/src/hooks/usePlan.js
+++ b/src/hooks/usePlan.js
@@ -1,22 +1,32 @@
'use client'
import { useContext, useEffect, useState } from 'react'
-import { usePathname, useRouter, useSearchParams } from 'next/navigation'
+import { usePathname, useRouter } from 'next/navigation'
import { useRecoilState, useResetRecoilState } from 'recoil'
-import { canvasState, currentCanvasPlanState, plansState } from '@/store/canvasAtom'
+import { canvasState, currentCanvasPlanState, plansState, canvasSettingState, currentObjectState, moduleSetupSurfaceState } from '@/store/canvasAtom'
import { useAxios } from '@/hooks/useAxios'
import { useMessage } from '@/hooks/useMessage'
import { useSwal } from '@/hooks/useSwal'
-import { useCanvas } from '@/hooks/useCanvas'
-import { SAVE_KEY } from '@/common/common'
-import { readImage, removeImage } from '@/lib/fileAction'
+import { POLYGON_TYPE, SAVE_KEY } from '@/common/common'
+import { removeImage } from '@/lib/fileAction'
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController'
import { outerLinePointsState } from '@/store/outerLineAtom'
import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom'
+import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
+import { compasDegAtom } from '@/store/orientationAtom'
+import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
+import { useCanvasPopupStatusController } from './common/useCanvasPopupStatusController'
+import { useCanvasMenu } from './common/useCanvasMenu'
+/**
+ * 플랜 처리 훅
+ * 플랜을 표시하는 탭 UI 전반적인 처리 로직 관리
+ * @param {*} params
+ * @returns
+ */
export function usePlan(params = {}) {
const { floorPlanState } = useContext(FloorPlanContext)
@@ -25,22 +35,39 @@ export function usePlan(params = {}) {
const [canvas, setCanvas] = useRecoilState(canvasState)
const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
- const [plans, setPlans] = useRecoilState(plansState) // 전체 plan
+ const [plans, setPlans] = useRecoilState(plansState)
const router = useRouter()
const pathname = usePathname()
const { swalFire } = useSwal()
const { getMessage } = useMessage()
- const { get, promisePost, promisePut, promiseDel, promiseGet } = useAxios()
+ const { get, post, promisePost, promisePut, promiseDel, promiseGet } = useAxios()
const { setEstimateContextState } = useEstimateController()
const resetOuterLinePoints = useResetRecoilState(outerLinePointsState)
const resetPlacementShapeDrawingPoints = useResetRecoilState(placementShapeDrawingPointsState)
+ const { fetchBasicSettings, basicSettingCopySave } = useCanvasSetting()
+ const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState)
+
/**
- * 마우스 포인터의 가이드라인을 제거합니다.
+ * 플랜 복사 시 모듈이 있을경우 모듈 데이터 복사하기 위한 처리
+ */
+ const { getModuleSelection } = useCanvasPopupStatusController()
+ const [compasDeg, setCompasDeg] = useRecoilState(compasDegAtom)
+ const [moduleSelectionDataStore, setModuleSelectionDataStore] = useRecoilState(moduleSelectionDataState)
+ const [selectedModules, setSelectedModules] = useRecoilState(selectedModuleState)
+ const { selectedMenu, setSelectedMenu } = useCanvasMenu()
+
+ //선택된 객체 초기화
+ const resetCurrentObject = useResetRecoilState(currentObjectState)
+ //선택된 모듈 배치면 초기화
+ const resetModuleSetupSurface = useResetRecoilState(moduleSetupSurfaceState)
+
+ /**
+ * 마우스 포인터의 가이드라인 제거
*/
const removeMouseLines = () => {
if (canvas?._objects.length > 0) {
@@ -50,26 +77,22 @@ export function usePlan(params = {}) {
canvas?.renderAll()
}
+ /**
+ * 현재 캔버스 데이터를 JSON 문자열로 직렬화
+ *
+ * @returns {string} 직렬화된 캔버스 데이터
+ */
const addCanvas = () => {
const objs = canvas?.toJSON(SAVE_KEY)
-
const str = JSON.stringify(objs)
-
- // canvas?.clear()
return str
-
- // setTimeout(() => {
- // // 역직렬화하여 캔버스에 객체를 다시 추가합니다.
- // canvas?.loadFromJSON(JSON.parse(str), function () {
- // // 모든 객체가 로드되고 캔버스에 추가된 후 호출됩니다.
- // console.log(canvas?.getObjects().filter((obj) => obj.name === 'roof'))
- // canvas?.renderAll() // 캔버스를 다시 그립니다.
- // })
- // }, 1000)
}
/**
* 현재 캔버스에 그려진 데이터를 추출
+ *
+ * @param {string} mode
+ * @returns {string} 캔버스 데이터
*/
const currentCanvasData = (mode = '') => {
removeMouseLines()
@@ -111,6 +134,9 @@ export function usePlan(params = {}) {
/**
* DB에 저장된 데이터를 canvas에서 사용할 수 있도록 포맷화
+ *
+ * @param {string} cs - DB에 저장된 캔버스 데이터 문자열
+ * @returns {string} 캔버스에서 사용할 수 있도록 포맷팅된 문자열
*/
const dbToCanvasFormat = (cs) => {
return cs.replace(/##/g, '"').replace(/∠/g, '∠').replace(/°/g, '°')
@@ -118,6 +144,9 @@ export function usePlan(params = {}) {
/**
* canvas의 데이터를 DB에 저장할 수 있도록 포맷화
+ *
+ * @param {string} cs - 캔버스 데이터 문자열
+ * @returns {string} DB 저장용 포맷 문자열
*/
const canvasToDbFormat = (cs) => {
return cs.replace(/"/g, '##')
@@ -125,6 +154,8 @@ export function usePlan(params = {}) {
/**
* 페이지 내 캔버스를 저장
+ *
+ * @param {boolean} saveAlert - 저장 완료 알림 표시 여부
*/
const saveCanvas = async (saveAlert = true) => {
const canvasStatus = currentCanvasData('save')
@@ -133,6 +164,10 @@ export function usePlan(params = {}) {
/**
* objectNo에 해당하는 canvas 목록을 조회
+ *
+ * @param {string} objectNo - 물건번호
+ * @param {string} planNo - 플랜번호
+ * @returns {Promise
} canvas 목록
*/
const getCanvasByObjectNo = async (objectNo, planNo) => {
return await get({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}` }).then((res) =>
@@ -152,6 +187,11 @@ export function usePlan(params = {}) {
/**
* 신규 plan 추가
*
+ * @param {string} userId - 사용자 ID
+ * @param {string} objectNo - 물건번호
+ * @param {boolean} isCopy - 복제 여부
+ * @param {boolean} isInitPlan - 초기 플랜 생성 여부
+ *
* case 1) 초기 플랜 생성 : isInitPlan = true, isCopy = false
* case 2) 빈 플랜 생성 : isInitPlan = false, isCopy = false
* case 3) 복제 플랜 생성 : isInitPlan = false, isCopy = true
@@ -169,42 +209,100 @@ export function usePlan(params = {}) {
objectNo: objectNo,
copyFlg: '0',
}
- await promisePost({ url: '/api/object/add-plan', data: planData })
- .then((res) => {
- let newPlan = {
- id: res.data.canvasId,
- objectNo: objectNo,
- planNo: res.data.planNo,
- userId: userId,
- canvasStatus: '',
- isCurrent: true,
- bgImageName: null,
- mapPositionAddress: null,
- }
- if (isInitPlan) {
- // 초기 플랜 생성인 경우 플랜 목록 초기화
- setCurrentCanvasPlan(newPlan)
- setPlans([newPlan])
- } else {
- if (isCopy) {
- // 복제 플랜 생성인 경우 현재 캔버스 데이터를 복제
- newPlan.canvasStatus = currentCanvasData()
- newPlan.bgImageName = currentCanvasPlan?.bgImageName ?? null
- newPlan.mapPositionAddress = currentCanvasPlan?.mapPositionAddress ?? null
- }
- setCurrentCanvasPlan(newPlan)
- setPlans((plans) => [...plans.map((plan) => ({ ...plan, isCurrent: false })), newPlan])
- swalFire({ text: getMessage('plan.message.save') })
+ const res = await promisePost({ url: '/api/object/add-plan', data: planData })
+ let newPlan = {
+ id: res.data.canvasId,
+ objectNo: objectNo,
+ planNo: res.data.planNo,
+ userId: userId,
+ canvasStatus: '',
+ isCurrent: true,
+ bgImageName: null,
+ mapPositionAddress: null,
+ }
+
+ if (isInitPlan) {
+ /* 초기 플랜 생성인 경우 플랜 목록 초기화 */
+ setCurrentCanvasPlan(newPlan)
+ setPlans([newPlan])
+
+ /* 플랜 추가 시 배치면초기설정 정보 조회 */
+ fetchBasicSettings(newPlan.planNo, null)
+ } else {
+ if (isCopy) {
+ const currentSelectedMenu = selectedMenu
+ /* 복제 플랜 생성인 경우 현재 캔버스 데이터를 복제 */
+ newPlan.canvasStatus = currentCanvasData()
+ newPlan.bgImageName = currentCanvasPlan?.bgImageName ?? null
+ newPlan.mapPositionAddress = currentCanvasPlan?.mapPositionAddress ?? null
+
+ /* 복제 시 배치면 초기설정 복사 */
+ basicSettingCopySave({
+ ...canvasSetting,
+ planNo: newPlan.planNo,
+ selectedRoofMaterial: {
+ ...canvasSetting.selectedRoofMaterial,
+ planNo: newPlan.planNo,
+ },
+ roofsData: canvasSetting.roofsData.map((roof) => ({
+ ...roof,
+ planNo: newPlan.planNo,
+ })),
+ })
+
+ /**
+ * 방위 데이터 복사
+ */
+ const sourceDegree = await getModuleSelection(1)
+ console.log('🚀 ~ sourceDegree:', sourceDegree)
+ const degreeData = {
+ objectNo,
+ planNo: parseInt(newPlan.planNo),
+ popupType: 1,
+ popupStatus: sourceDegree.popupStatus,
}
- })
- .catch((error) => {
- swalFire({ text: error.response.data.message, icon: 'error' })
- })
+ console.log('🚀 ~ postObjectPlan ~ degreeData:', degreeData)
+ await post({ url: `/api/v1/canvas-popup-status`, data: degreeData })
+ /** 리코일 세팅 */
+ setCompasDeg(sourceDegree.popupStatus)
+
+ /**
+ * 모듈 선택 데이터 복사
+ */
+ const moduleSelectionData = await getModuleSelection(2)
+ console.log('🚀 ~ moduleSelectionData:', moduleSelectionData)
+ const moduleStatus = moduleSelectionData.popupStatus.replace(/"/g, '\"')
+ const moduleData = {
+ objectNo,
+ planNo: parseInt(newPlan.planNo),
+ popupType: 2,
+ popupStatus: moduleStatus,
+ }
+ console.log('🚀 ~ postObjectPlan ~ moduleData:', moduleData)
+ await post({ url: `/api/v1/canvas-popup-status`, data: moduleData })
+ const copyData = JSON.parse(moduleStatus)
+ console.log('🚀 ~ postObjectPlan ~ copyData:', copyData)
+
+ /** 리코일 세팅 */
+ setModuleSelectionDataStore(copyData)
+ if (copyData.module) setSelectedModules(copyData.module)
+ setSelectedMenu(currentSelectedMenu)
+ } else {
+ setSelectedMenu('placement')
+ }
+ setCurrentCanvasPlan(newPlan)
+ setPlans((plans) => [...plans.map((plan) => ({ ...plan, isCurrent: false })), newPlan])
+
+ swalFire({ text: getMessage('plan.message.save') })
+ }
}
/**
* id에 해당하는 canvas 데이터를 수정
+ *
+ * @param {string} canvasStatus - 캔버스 데이터
+ * @param {boolean} saveAlert - 저장 완료 알림 표시 여부
*/
const putCanvasStatus = async (canvasStatus, saveAlert = true) => {
const planData = {
@@ -225,6 +323,9 @@ export function usePlan(params = {}) {
/**
* id에 해당하는 canvas 데이터를 삭제
+ *
+ * @param {string} id - canvas ID
+ * @returns {Promise} 결과
*/
const delCanvasById = async (id) => {
return await promiseDel({ url: `/api/canvas-management/canvas-statuses/by-id/${id}` })
@@ -232,6 +333,9 @@ export function usePlan(params = {}) {
/**
* objectNo에 해당하는 canvas 데이터들을 삭제
+ *
+ * @param {string} objectNo - 물건번호
+ * @returns {Promise} 결과
*/
const delCanvasByObjectNo = async (objectNo) => {
return await promiseDel({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}` })
@@ -240,12 +344,14 @@ export function usePlan(params = {}) {
/**
* plan 이동
* 현재 plan의 작업상태를 저장 후 이동
+ *
+ * @param {string} newCurrentId - 이동할 plan ID
*/
const handleCurrentPlan = async (newCurrentId) => {
const planNo = plans?.find((obj) => obj.id === newCurrentId).planNo
const objectNo = floorPlanState.objectNo
- //견적서 or 발전시뮬
+ //견적서 or 발전시뮬
if (pathname !== '/floor-plan') {
await promiseGet({ url: `/api/estimate/${objectNo}/${planNo}/detail` })
.then((res) => {
@@ -279,7 +385,7 @@ export function usePlan(params = {}) {
}
} else {
// 발전시뮬레이션
- if (estimateDetail.estimateDate !== null) {
+ if (estimateDetail.estimateDate !== null && estimateDetail.docNo) {
setCurrentCanvasPlan(plans.find((plan) => plan.id === newCurrentId))
setPlans((plans) => plans.map((plan) => ({ ...plan, isCurrent: plan.id === newCurrentId })))
} else {
@@ -298,7 +404,6 @@ export function usePlan(params = {}) {
} else {
if (!currentCanvasPlan || currentCanvasPlan.id !== newCurrentId) {
await saveCanvas(true)
-
clearRecoilState()
}
setCurrentCanvasPlan(plans.find((plan) => plan.id === newCurrentId))
@@ -309,27 +414,32 @@ export function usePlan(params = {}) {
useEffect(() => {
setSelectedPlan(currentCanvasPlan)
handleCurrentPlanUrl()
- // setBgImage()
+ resetCurrentObject()
+ resetModuleSetupSurface()
}, [currentCanvasPlan])
+ /**
+ * clear가 필요한 recoil state 관리
+ */
const clearRecoilState = () => {
- //clear가 필요한 recoil state 관리
resetOuterLinePoints()
resetPlacementShapeDrawingPoints()
}
+ /**
+ * 현재 plan의 정보를 URL에 추가
+ */
const handleCurrentPlanUrl = () => {
if (currentCanvasPlan?.planNo && currentCanvasPlan?.objectNo)
router.push(`${pathname}?pid=${currentCanvasPlan?.planNo}&objectNo=${currentCanvasPlan?.objectNo}`)
}
- const setBgImage = () => {
- // readImage(selectedPlan?.id)
- }
-
/**
* 새로운 plan 생성
* 현재 plan의 데이터가 있을 경우 현재 plan 저장 및 복제 여부를 확인
+ *
+ * @param {string} userId - 사용자 ID
+ * @param {string} objectNo - 물건번호
*/
const handleAddPlan = async (userId, objectNo) => {
if (currentCanvasPlan?.id) {
@@ -351,6 +461,11 @@ export function usePlan(params = {}) {
/**
* 물건번호(object) plan 삭제 (canvas 삭제 전 planNo 삭제)
+ *
+ * @param {string} userId - 사용자 ID
+ * @param {string} objectNo - 물건번호
+ * @param {string} planNo - 플랜번호
+ * @returns {Promise} 결과
*/
const deleteObjectPlan = async (userId, objectNo, planNo) => {
return await promiseDel({ url: `/api/object/plan/${objectNo}/${planNo}?userId=${userId}` })
@@ -365,6 +480,9 @@ export function usePlan(params = {}) {
/**
* plan 삭제
+ *
+ * @param {Event} e - 이벤트
+ * @param {Object} targetPlan - 삭제할 plan
*/
const handleDeletePlan = async (e, targetPlan) => {
e.stopPropagation() // 이벤트 버블링 방지
@@ -376,24 +494,35 @@ export function usePlan(params = {}) {
.then((res) => {
setPlans((plans) => plans.filter((plan) => plan.id !== targetPlan.id))
removeImage(currentCanvasPlan.id)
+
+ /* 플랜 삭제 후 배치면 초기설정 삭제 */
+ deleteBasicSettings(targetPlan.objectNo, targetPlan.planNo)
+
swalFire({ text: getMessage('plan.message.delete') })
})
.catch((error) => {
swalFire({ text: error.message, icon: 'error' })
})
- // 삭제 후 last 데이터에 포커싱
+ /* 삭제 후 last 데이터에 포커싱 */
const lastPlan = plans.filter((plan) => plan.id !== targetPlan.id).at(-1)
if (!lastPlan) {
setCurrentCanvasPlan(null)
} else if (targetPlan.id !== lastPlan.id) {
setCurrentCanvasPlan(lastPlan)
setPlans((plans) => plans.map((plan) => ({ ...plan, isCurrent: plan.id === lastPlan.id })))
+
+ /* 플랜 삭제 시 그 전 플랫의 배치면초기설정 정보 조회 */
+ fetchBasicSettings(lastPlan.planNo, null)
}
}
/**
* plan 조회
+ *
+ * @param {string} userId - 사용자 ID
+ * @param {string} objectNo - 물건번호
+ * @param {string} planNo - 플랜번호
*/
const loadCanvasPlanData = async (userId, objectNo, planNo) => {
console.log('🚀 ~ loadCanvasPlanData ~ userId, objectNo, planNo:', userId, objectNo, planNo)
@@ -417,8 +546,10 @@ export function usePlan(params = {}) {
/**
* plan canvasStatus 불러오기
- *
* 견적서/발전시뮬레이션에서 플랜 이동 시 현재 플랜의 canvasStatus를 불러오기 위해 사용
+ *
+ * @param {string} objectNo - 물건번호
+ * @param {string} planNo - 플랜번호
*/
const reloadCanvasStatus = async (objectNo, planNo) => {
if (pathname === '/floor-plan/estimate/5' || pathname === '/floor-plan/simulator/6') {
@@ -432,10 +563,19 @@ export function usePlan(params = {}) {
}
/**
- * 현재 plan 이동 -> 새로운 링크로 이동
+ * 플랜 삭제 시 배치면 초기설정 데이터 삭제
+ *
+ * @param {string} objectNo - 물건번호
+ * @param {string} planNo - 플랜번호
*/
- const handlePlanMove = () => {
- router.push(`${pathname}?objectNo=${floorPlanState.objectNo}&pid=${currentCanvasPlan?.planNo}`)
+ const deleteBasicSettings = async (objectNo, planNo) => {
+ try {
+ await promiseDel({ url: `/api/canvas-management/canvas-basic-settings/delete-basic-settings/${objectNo}/${planNo}` })
+ } catch (error) {
+ /* 오류를 무시하고 계속 진행 */
+ console.log('Basic settings delete failed or not found:', error)
+ // swalFire({ text: error.message, icon: 'error' })
+ }
}
return {
diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js
index 50470060..54de877b 100644
--- a/src/hooks/usePolygon.js
+++ b/src/hooks/usePolygon.js
@@ -7,7 +7,7 @@ import { isSamePoint, removeDuplicatePolygons } from '@/util/qpolygon-utils'
import { flowDisplaySelector } from '@/store/settingAtom'
import { fontSelector } from '@/store/fontAtom'
import { QLine } from '@/components/fabric/QLine'
-import { POLYGON_TYPE } from '@/common/common'
+import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
export const usePolygon = () => {
const canvas = useRecoilValue(canvasState)
@@ -17,16 +17,16 @@ export const usePolygon = () => {
const currentAngleType = useRecoilValue(currentAngleTypeSelector)
const pitchText = useRecoilValue(pitchTextSelector)
- const addPolygon = (points, options) => {
+ const addPolygon = (points, options, isAddCanvas = true) => {
const polygon = new QPolygon(points, {
...options,
fontSize: lengthTextFontOptions.fontSize.value,
fill: options.fill || 'transparent',
stroke: options.stroke || '#000000',
- selectable: true,
+ // selectable: true,
})
- canvas?.add(polygon)
+ if (isAddCanvas) canvas?.add(polygon)
addLengthText(polygon)
return polygon
@@ -48,6 +48,7 @@ export const usePolygon = () => {
canvas.remove(text)
})
const lines = polygon.lines
+ polygon.texts = []
lines.forEach((line, i) => {
const length = line.getLength()
@@ -102,7 +103,7 @@ export const usePolygon = () => {
parent: polygon,
name: 'lengthText',
})
-
+ polygon.texts.push(text)
canvas.add(text)
})
@@ -172,8 +173,9 @@ export const usePolygon = () => {
/**
* poolygon의 방향에 따라 화살표를 추가한다.
* @param polygon
+ * @param showDirectionText
*/
- const drawDirectionArrow = (polygon) => {
+ const drawDirectionArrow = (polygon, showDirectionText = true) => {
if (polygon.points.length < 3) {
return
}
@@ -319,17 +321,16 @@ export const usePolygon = () => {
pitch: polygon.roofMaterial?.pitch ?? 4,
parentId: polygon.id,
})
-
arrow.setViewLengthText(false)
polygon.arrow = arrow
polygon.canvas.add(arrow)
polygon.canvas.renderAll()
- drawDirectionStringToArrow2(polygon)
+ drawDirectionStringToArrow2(polygon, showDirectionText)
// drawDirectionStringToArrow()
}
//arrow의 compass 값으로 방향 글자 설정 필요
- const drawDirectionStringToArrow2 = (polygon) => {
+ const drawDirectionStringToArrow2 = (polygon, showDirectionText) => {
const { direction, surfaceCompass, moduleCompass, arrow } = polygon
if (moduleCompass === null || moduleCompass === undefined) {
const textObj = new fabric.Text(`${currentAngleType === ANGLE_TYPE.SLOPE ? arrow.pitch : getDegreeByChon(arrow.pitch)}${pitchText}`, {
@@ -510,24 +511,27 @@ export const usePolygon = () => {
text = text + (sameDirectionCnt.length + 1)
polygon.set('directionText', text)
- const textObj = new fabric.Text(`${text} (${currentAngleType === ANGLE_TYPE.SLOPE ? arrow.pitch : getDegreeByChon(arrow.pitch)}${pitchText})`, {
- fontFamily: flowFontOptions.fontFamily.value,
- fontWeight: flowFontOptions.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
- fontStyle: flowFontOptions.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
- fontSize: flowFontOptions.fontSize.value,
- fill: flowFontOptions.fontColor.value,
- pitch: arrow.pitch,
- originX: 'center',
- originY: 'center',
- name: 'flowText',
- originText: text,
- selectable: false,
- left: arrow.stickeyPoint.x,
- top: arrow.stickeyPoint.y,
- parent: arrow,
- parentId: arrow.id,
- visible: isFlowDisplay,
- })
+ const textObj = new fabric.Text(
+ `${showDirectionText && text} (${currentAngleType === ANGLE_TYPE.SLOPE ? arrow.pitch : getDegreeByChon(arrow.pitch)}${pitchText})`,
+ {
+ fontFamily: flowFontOptions.fontFamily.value,
+ fontWeight: flowFontOptions.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
+ fontStyle: flowFontOptions.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
+ fontSize: flowFontOptions.fontSize.value,
+ fill: flowFontOptions.fontColor.value,
+ pitch: arrow.pitch,
+ originX: 'center',
+ originY: 'center',
+ name: 'flowText',
+ originText: text,
+ selectable: false,
+ left: arrow.stickeyPoint.x,
+ top: arrow.stickeyPoint.y,
+ parent: arrow,
+ parentId: arrow.id,
+ visible: isFlowDisplay,
+ },
+ )
polygon.canvas.add(textObj)
}
@@ -753,6 +757,22 @@ export const usePolygon = () => {
polygon.set({ visible: false })
let innerLines = [...polygon.innerLines]
+ // innerLine이 세팅이 안되어있는경우 찾아서 세팅한다.
+ if (!innerLines || innerLines.length === 0) {
+ let innerLineTypes = Object.keys(LINE_TYPE.SUBLINE).map((key, value) => LINE_TYPE.SUBLINE[key])
+ polygon.innerLines = canvas
+ .getObjects()
+ .filter(
+ (obj) =>
+ obj.type === 'QLine' &&
+ obj.attributes?.type !== 'pitchSizeLine' &&
+ obj.attributes?.roofId === polygon.id &&
+ (innerLineTypes.includes(obj.name) || !obj.name),
+ )
+
+ innerLines = [...polygon.innerLines]
+ }
+
canvas.renderAll()
let polygonLines = [...polygon.lines]
const roofs = []
@@ -909,6 +929,29 @@ export const usePolygon = () => {
const allLines = [...polygonLines, ...innerLines]
+ // 2025-02-19 대각선은 케라바, 직선은 용마루로 세팅
+ innerLines.forEach((innerLine) => {
+ const startPoint = innerLine.startPoint
+ const endPoint = innerLine.endPoint
+
+ // startPoint와 endPoint의 각도가 0,90,180,270이면 직선으로 판단
+ if (Math.abs(startPoint.x - endPoint.x) < 2 || Math.abs(startPoint.y - endPoint.y) < 2) {
+ if (!innerLine.attributes || !innerLine.attributes.type) {
+ innerLine.attributes = {
+ ...innerLine.attributes,
+ type: LINE_TYPE.SUBLINE.RIDGE,
+ }
+ }
+ } else {
+ if (!innerLine.attributes || !innerLine.attributes.type) {
+ innerLine.attributes = {
+ ...innerLine.attributes,
+ type: LINE_TYPE.SUBLINE.GABLE,
+ }
+ }
+ }
+ })
+
/**
* 왼쪽 상단을 startPoint로 전부 변경
*/
@@ -940,15 +983,15 @@ export const usePolygon = () => {
/*line.set({ strokeWidth: 5, stroke: 'green' })
canvas.add(line)
canvas.renderAll()*/
- const startPoint = line.startPoint // 시작점
- let arrivalPoint = line.endPoint // 도착점
+ const startPoint = { ...line.startPoint } // 시작점
+ let arrivalPoint = { ...line.endPoint } // 도착점
let currentPoint = startPoint
- const roofPoints = [startPoint]
+ let roofPoints = [startPoint]
- const startLine = line
- const visitPoints = [startPoint]
- const visitLines = [startLine]
+ let startLine = line
+ let visitPoints = [startPoint]
+ let visitLines = [startLine]
let notVisitedLines = []
let cnt = 0
@@ -976,7 +1019,10 @@ export const usePolygon = () => {
if (notVisitedLines.length === 0) {
break
} else {
- // nextLines = [...notVisitedLines.shift().line]
+ let notVisitedLine = notVisitedLines.shift()
+ roofPoints = [...notVisitedLine.roofPoints]
+ currentPoint = { ...notVisitedLine.currentPoint }
+ continue
}
}
@@ -1017,6 +1063,7 @@ export const usePolygon = () => {
currentPoint = { ...minDistancePoint }
roofPoints.push(currentPoint)
cnt++
+
if (cnt > 100) {
break
}
@@ -1056,6 +1103,8 @@ export const usePolygon = () => {
}
})
+ // blue로 생성된 것들은 대표라인이 될 수 없음.
+ representLines = representLines.filter((line) => line.stroke !== 'blue')
// representLines중 가장 긴 line을 찾는다.
representLines.forEach((line) => {
if (!representLine) {
diff --git a/src/lib/authActions.js b/src/lib/authActions.js
index e1bbd192..5a63d684 100644
--- a/src/lib/authActions.js
+++ b/src/lib/authActions.js
@@ -9,7 +9,7 @@ import { sessionOptions } from './session'
export async function logout() {
const session = await getSession()
session.destroy()
- redirect('/login')
+ // redirect('/login')
}
export async function getSession() {
@@ -58,32 +58,3 @@ export async function login() {
redirect('/')
}
}
-
-export const customSetMenuNumber = async ({ objectNo, pid, menuNum, callback = () => {} }) => {
- let db = null
-
- if (!db) {
- db = await open({
- filename: 'qcast3.global.sqlite',
- driver: sqlite3.Database,
- })
- }
-
- const chkSql = `SELECT menu_num FROM current_menu WHERE object_no = ? AND pid = ?`
- const prevMenuNum = await getInstance().get(chkSql, objectNo, pid)
-
- if (prevMenuNum) {
- if (prevMenuNum > menuNum) {
- callback()
- } else {
- const sql = `UPDATE current_menu SET menu_num = ? WHERE object_no = ? AND pid = ?`
- await getInstance().run(sql, menuNum, objectNo, pid)
-
- setMenuNumber(menuNum)
- }
- } else {
- const sql = `INSERT INTO current_menu (object_no, pid, menu_num) VALUES (?, ?, ?)`
- await getInstance().run(sql, objectNo, pid, menuNum)
- setMenuNumber(menuNum)
- }
-}
diff --git a/src/lib/imageActions.js b/src/lib/imageActions.js
new file mode 100644
index 00000000..b085b1a2
--- /dev/null
+++ b/src/lib/imageActions.js
@@ -0,0 +1,67 @@
+'use server'
+
+import sqlite3 from 'sqlite3'
+import { open } from 'sqlite'
+
+/**
+ * 캔바스 배경 이미지가 설정되면 데이터를 저장한다.
+ * @param {*} param0
+ */
+export const setBackGroundImage = async ({ objectId, planNo, imagePath }) => {
+ let db = null
+
+ if (!db) {
+ db = await open({
+ filename: 'qcast3.database.sqlite',
+ driver: sqlite3.Database,
+ })
+ }
+
+ const fetchSql = `SELECT * FROM background_image WHERE object_id = '${objectId}' AND plan_no = '${planNo}'`
+ const result = await db.get(fetchSql)
+ if (result) {
+ const updateSql = `UPDATE background_image SET path = '${imagePath}' WHERE object_id = '${objectId}' AND plan_no = '${planNo}'`
+ await db.run(updateSql)
+ } else {
+ const insertSql = `INSERT INTO background_image (object_id, plan_no, path) VALUES ('${objectId}', '${planNo}', '${imagePath}')`
+ await db.run(insertSql)
+ }
+}
+
+/**
+ * 캔바스 배경 이미지 데이터를 조회한다.
+ * @param {*} param0
+ * @returns
+ */
+export const getBackGroundImage = async ({ objectId, planNo }) => {
+ let db = null
+
+ if (!db) {
+ db = await open({
+ filename: 'qcast3.database.sqlite',
+ driver: sqlite3.Database,
+ })
+ }
+
+ const sql = `SELECT * FROM background_image WHERE object_id = '${objectId}' AND plan_no = '${planNo}'`
+ const result = await db.get(sql)
+ return result
+}
+
+/**
+ * 캔바스 배경 이미지 데이터를 삭제한다.
+ * @param {*} param0
+ */
+export const deleteBackGroundImage = async ({ objectId, planNo }) => {
+ let db = null
+
+ if (!db) {
+ db = await open({
+ filename: 'qcast3.database.sqlite',
+ driver: sqlite3.Database,
+ })
+ }
+
+ const sql = `DELETE FROM background_image WHERE object_id = '${objectId}' AND plan_no = '${planNo}'`
+ await db.run(sql)
+}
diff --git a/src/locales/ja.json b/src/locales/ja.json
index fd2626b4..0028a047 100644
--- a/src/locales/ja.json
+++ b/src/locales/ja.json
@@ -2,14 +2,14 @@
"hi": "こんにちは",
"welcome": "ようこそ。 {0}さん",
"header.menus.home": "ホーム",
- "header.menus.management": "オブジェクトと図面の管理",
- "header.menus.management.newStuff": "新規物件登録",
+ "header.menus.management": "見積書管理画面",
+ "header.menus.management.newStuff": "新規見積登録",
"header.menus.management.detail": "物件詳細",
- "header.menus.management.stuffList": "見積状況",
+ "header.menus.management.stuffList": "物件検索",
"header.menus.community": "コミュニティ",
"header.menus.community.notice": "お知らせ",
"header.menus.community.faq": "FAQ",
- "header.menus.community.archive": "文書ダウンロード",
+ "header.menus.community.archive": "各種資料ダウンロード",
"header.logout": "ログアウト",
"header.go": "移動",
"header.online.warranty.system": "オンライン保証システム",
@@ -26,8 +26,8 @@
"modal.placement.initial.setting.size.actual.info": "屋根の外周寸法を入力して作画する場合選択",
"modal.placement.initial.setting.size.none.pitch": "陸屋根",
"modal.placement.initial.setting.size.none.pitch.info": "傾斜のない平面形状の屋根にパネルを配置する場合に選択",
- "modal.placement.initial.setting.roof.angle.setting": "角度設定",
- "modal.placement.initial.setting.roof.pitch": "傾斜",
+ "modal.placement.initial.setting.roof.angle.setting": "勾配設定",
+ "modal.placement.initial.setting.roof.pitch": "寸",
"modal.placement.initial.setting.roof.angle": "角度",
"modal.placement.initial.setting.roof.material": "屋根材選択(単位mm)",
"modal.placement.initial.setting.roof.material.info": "対応可能な屋根材や足場は限定されますので、必ず事前マニュアルをご確認ください。",
@@ -37,7 +37,7 @@
"modal.roof.shape.setting.patten.a": "Aパターン",
"modal.roof.shape.setting.patten.b": "Bパターン",
"modal.roof.shape.setting.side": "別に設定",
- "plan.menu.roof.cover": "屋根カバー",
+ "plan.menu.roof.cover": "屋根作図",
"plan.menu.roof.cover.outline.drawing": "外壁線を描く",
"plan.menu.roof.cover.roof.shape.setting": "屋根形状の設定",
"plan.menu.roof.cover.roof.shape.passivity.setting": "屋根形状の手動設定",
@@ -82,9 +82,9 @@
"modal.placement.surface.drawing.diagonal": "対角線",
"modal.placement.surface.drawing.fix": "配置面確定",
"plan.menu.placement.surface.arrangement": "面形状の配置",
- "plan.menu.placement.surface.object": "モジュール配置",
+ "plan.menu.placement.surface.object": "オブジェクト配置",
"plan.menu.placement.surface.all.remove": "配置面全体を削除",
- "plan.menu.module.circuit.setting": "モジュール、回路構成",
+ "plan.menu.module.circuit.setting": "モジュール配置、回路構成",
"plan.menu.module.circuit.setting.default": "モジュール/架台設定",
"modal.module.basic.setting.orientation.setting": "方位設定",
"modal.module.basic.setting.orientation.setting.info": "※シミュレーション計算用方位を指定します。南の方位を設定してください。",
@@ -107,7 +107,7 @@
"modal.module.basic.setting.module.enforce.construction": "強化施工",
"modal.module.basic.setting.module.multiple.construction": "多設施工",
"modal.module.basic.setting.module.eaves.bar.fitting": "軒カバーの設置",
- "modal.module.basic.setting.module.blind.metal.fitting": "積雪防止金具設置",
+ "modal.module.basic.setting.module.blind.metal.fitting": "落雪防止金具設置",
"modal.module.basic.setting.module.select": "モジュール/架台選択",
"modal.module.basic.setting.module.placement": "モジュールの配置",
"modal.module.basic.setting.module.placement.select.fitting.type": "設置形態を選択してください。",
@@ -148,18 +148,18 @@
"modal.circuit.trestle.setting.circuit.allocation.auto": "自動回路割り当て",
"modal.circuit.trestle.setting.circuit.allocation.passivity": "手動回路割り当て",
"modal.circuit.trestle.setting.circuit.allocation.passivity.circuit": "回路",
- "modal.circuit.trestle.setting.circuit.allocation.passivity.series": "시리즈(JA)",
- "modal.circuit.trestle.setting.circuit.allocation.passivity.name": "명칭(JA)",
+ "modal.circuit.trestle.setting.circuit.allocation.passivity.series": "PCSシリーズ",
+ "modal.circuit.trestle.setting.circuit.allocation.passivity.name": "型番",
"modal.circuit.trestle.setting.circuit.allocation.passivity.info": "同じ回路のモジュールを選択状態にした後、[番号確定]ボタンを押すと番号が割り当てられます。",
"modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional": "選択したパワーコンディショナー",
"modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num": "設定する回路番号(1~)",
"modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.info": "標準回路{0}章~{1}章",
"modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional.reset": "選択したパワーコンディショナーの回路番号の初期化",
- "modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional.reset.info": "선택된 파워 컨디셔너의 회로할당을 초기화합니다.(JA)",
+ "modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional.reset.info": "選択したパワーコンディショナーの回路割り当てを初期化します。",
"modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.reset": "すべての回路番号の初期化",
- "modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.reset.info": "회로 할당의 설정을 초기화합니다.(JA)",
- "modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.validation.error01": "배치가능 매수를 초과합니다. 파워컨디셔너를 다시 선택해 주세요.(JA)",
- "modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.validation.error02": "시리즈를 선택해주세요.(JA)",
+ "modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.reset.info": "回路割り当ての設定を初期化します。",
+ "modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.validation.error01": "接続可能枚数を超えています。パワーコンディショナーをもう一度選択してください。",
+ "modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.validation.error02": "シリーズを選択してください。",
"modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num.fix": "番号確定",
"modal.circuit.trestle.setting.step.up.allocation": "昇圧設定",
"modal.circuit.trestle.setting.step.up.allocation.serial.amount": "シリアル枚数",
@@ -174,10 +174,11 @@
"modal.roof.alloc.info": "※配置面初期設定で保存した[基本屋根材]を変更したり、屋根材を追加して割り当てることができます。",
"modal.roof.alloc.default.roof.material": "基本屋根材",
"modal.roof.alloc.select.roof.material": "屋根材の選択",
- "modal.roof.alloc.select.parallel": "並列式",
- "modal.roof.alloc.select.stairs": "階段式",
+ "modal.roof.alloc.add.roof.material": "屋根材 追加",
+ "modal.roof.alloc.select.parallel": "筋配置",
+ "modal.roof.alloc.select.stairs": "千鳥配置",
"modal.roof.alloc.apply": "選択した屋根材として割り当て",
- "plan.menu.estimate.docDown": "文書のダウンロード",
+ "plan.menu.estimate.docDown": "各種資料ダウンロード",
"plan.menu.estimate.save": "保存",
"plan.menu.estimate.reset": "初期化",
"plan.menu.estimate.copy": "見積書のコピー",
@@ -228,7 +229,7 @@
"modal.dormer.offset.info": "移動する距離と方向を入力してください。",
"modal.common.save": "保存",
"modal.common.add": "追加",
- "modal.common.prev": "以前",
+ "modal.common.prev": "前に戻る",
"modal.common.next": "次",
"modal.canvas.setting.font.plan.edit": "フォントとサイズの変更",
"modal.canvas.setting.font.plan.edit.word": "文字フォントの変更",
@@ -238,9 +239,9 @@
"modal.canvas.setting.font.plan.absorption": "吸着範囲の設定",
"modal.canvas.setting.font.plan.absorption.point": "吸着点",
"modal.canvas.setting.font.plan.absorption.small": "極小",
- "modal.canvas.setting.font.plan.absorption.small.semi": "牛",
+ "modal.canvas.setting.font.plan.absorption.small.semi": "小",
"modal.canvas.setting.font.plan.absorption.medium": "中",
- "modal.canvas.setting.font.plan.absorption.large": "ティーン",
+ "modal.canvas.setting.font.plan.absorption.large": "大",
"modal.canvas.setting.font.plan.absorption.dimension.line": "寸法線の設定",
"modal.canvas.setting.font.plan.absorption.dimension.line.font.size": "寸法線の太さ",
"modal.canvas.setting.font.plan.absorption.dimension.line.color": "寸法線の色",
@@ -269,9 +270,13 @@
"modal.canvas.setting.wallline.properties.setting.info": "※属性を変更する外壁線を選択し、軒で設定またはケラバで設定\nボタンをクリックして設定値を適用してください。\n",
"modal.canvas.setting.wallline.properties.setting.eaves": "軒で設定",
"modal.canvas.setting.wallline.properties.setting.edge": "ケラバに設定",
+ "modal.canvas.setting.wallline.properties.setting.ridge": "棟に設定",
+ "modal.canvas.setting.roofline.properties.setting": "屋根線属性設定",
+ "modal.canvas.setting.roofline.properties.setting.info": "※ 属性を変更する配置面の線を選択し、軒線の設定 けらば線の設定\n 棟線の設定ボタンをクリックして設定値を適用してください。",
+ "modal.canvas.setting.roofline.properties.setting.not.setting": "設定していないラインが存在します。",
"modal.eaves.gable.edit": "軒/ケラバ変更",
"modal.eaves.gable.edit.basic": "通常",
- "modal.eaves.gable.edit.wall.merge.info": "河屋などの壁に面する屋根を作成します。",
+ "modal.eaves.gable.edit.wall.merge.info": "下屋などの壁に面する屋根を作成します。",
"modal.wallline.offset.setting": "外壁の編集とオフセット",
"modal.wallline.offset.setting.wallline.edit": "外壁の編集",
"modal.wallline.offset.setting.wallline.edit.info": "辺と始点を選択して長さと方向を指定してください。",
@@ -288,9 +293,11 @@
"modal.object.setting.height": "縦長",
"modal.object.setting.area.cross": "エリア交差",
"modal.object.setting.size.setting": "サイズ設定",
- "modal.object.setting.agreement.depth": "棟の長さ・深さ",
- "modal.object.setting.offset.depth": "出幅(深さ)",
- "modal.object.setting.offset.width": "出幅(幅)",
+ "modal.object.setting.agreement.depth": "棟の長さ",
+ "modal.object.setting.offset.depth": "棟の出幅",
+ "modal.object.setting.size.width": "幅",
+ "modal.object.setting.offset.width": "幅の出幅",
+ "modal.object.setting.offset.slope": "勾配",
"modal.object.setting.direction.select": "方向の選択",
"modal.placement.surface.setting.info": "ⓘ①の長さ入力後、対角線長を入力すると②の長さを自動計算します。",
"modal.placement.surface.setting.diagonal.length": "斜めの長さ",
@@ -421,7 +428,8 @@
"modal.module.circuit.number.edit": "モジュール一括回路番号の変更",
"modal.module.circuit.number.edit.info": "回路番号を入力してください。",
"modal.module.circuit.number": "回路番号",
- "modal.module.can.not.edit": "회로 구성을 완료한 모듈은 변경할 수 없습니다.(JA)",
+ "modal.module.pcs.error1": "併設用PCSは単独で選択することはできません。,",
+ "modal.module.can.not.edit": "回路構成を完了したモジュールは変更できません。,",
"modal.line.property.change": "変更する属性を選択してください。",
"modal.line.property.change.unselect": "変更するラインを選択してください。",
"modal.line.property.change.confirm": "プロパティを変更しますか?",
@@ -549,14 +557,14 @@
"board.notice.sub.title": "お知らせ一覧",
"board.faq.title": "FAQ",
"board.faq.sub.title": "FAQリスト",
- "board.archive.title": "資料のダウンロード",
- "board.archive.sub.title": "文書一覧",
+ "board.archive.title": "各種資料ダウンロード",
+ "board.archive.sub.title": "見積書一覧",
"board.list.header.rownum": "番号",
"board.list.header.title": "タイトル",
"board.list.header.regDt": "登録日",
"board.sub.search.placeholder": "検索語を入力してください。",
"board.sub.search.result": "{0}の合計{1}件の投稿が検索されました。",
- "board.sub.search.archive.result": "{0}の合計{1}件の文書が検索されました。",
+ "board.sub.search.archive.result": "{0}の合計{1}件の見積が検索されました。",
"board.sub.total": "全体",
"board.sub.fileList": "添付ファイル一覧",
"board.sub.updDt": "更新",
@@ -612,9 +620,9 @@
"join.sub1.addr": "住所",
"join.sub1.addr_placeholder": "全角50文字以内",
"join.sub1.telNo": "電話番号",
- "join.sub1.telNo_placeholder": "00-0000-0000",
+ "join.sub1.telNo_placeholder": "00 0000 0000",
"join.sub1.fax": "FAX番号",
- "join.sub1.fax_placeholder": "00-0000-0000",
+ "join.sub1.fax_placeholder": "00 0000 0000",
"join.sub1.bizNo": "法人番号",
"join.sub2.title": "担当者情報",
"join.sub2.userNm": "担当者名",
@@ -622,9 +630,9 @@
"join.sub2.userId": "申請ID",
"join.sub2.email": "メールアドレス",
"join.sub2.telNo": "電話番号",
- "join.sub2.telNo_placeholder": "00-0000-0000",
+ "join.sub2.telNo_placeholder": "00 0000 0000",
"join.sub2.fax": "FAX番号",
- "join.sub2.fax_placeholder": "00-0000-0000",
+ "join.sub2.fax_placeholder": "00 0000 0000",
"join.sub2.category": "部署名",
"join.btn.login_page": "ログイン画面に移動",
"join.btn.approval_request": "ID承認要求",
@@ -636,15 +644,15 @@
"stuff.gridHeader.lastEditDatetime": "更新日時",
"stuff.gridHeader.objectNo": "物件番号",
"stuff.gridHeader.planTotCnt": "プラン数",
- "stuff.gridHeader.objectName": "商品名",
+ "stuff.gridHeader.objectName": "物件名",
"stuff.gridHeader.saleStoreId": "代理店ID",
"stuff.gridHeader.saleStoreName": "代理店名",
"stuff.gridHeader.address": "物件住所",
- "stuff.gridHeader.dispCompanyName": "見積もり",
+ "stuff.gridHeader.dispCompanyName": "見積先",
"stuff.gridHeader.receiveUser": "担当者",
"stuff.gridHeader.specificationConfirmDate": "仕様確認日",
"stuff.gridHeader.createDatetime": "登録日",
- "stuff.gridData.tempObjectNo": "一時保存物",
+ "stuff.gridData.tempObjectNo": "一次保存案件",
"stuff.message.periodError": "最大1年閲覧可能です。",
"stuff.addressPopup.title": "郵便番号",
"stuff.addressPopup.placeholder": "郵便番号の7桁を入力してください。",
@@ -656,7 +664,7 @@
"stuff.addressPopup.btn1": "閉じる",
"stuff.addressPopup.btn2": "住所適用",
"stuff.planReqPopup.title": "設計依頼のインポート",
- "stuff.temp.subTitle": "商品情報",
+ "stuff.temp.subTitle": "物件情報",
"stuff.temp.subTitle2": "作図",
"stuff.detail.header.notExistObjectNo": "存在しないものです。",
"stuff.detail.header.successCopy": "物件番号がコピーされました。",
@@ -685,9 +693,9 @@
"stuff.detail.standardWindSpeedIdSpan": "m/s以下",
"stuff.detail.btn.windSpeedPop": "風速選択",
"stuff.detail.verticalSnowCover": "垂直積雪量",
- "stuff.detail.coldRegionFlg": "寒冷地対策施行",
- "stuff.detail.surfaceType": "面粗度",
- "stuff.detail.saltAreaFlg": "塩害地域用アイテムの使用",
+ "stuff.detail.coldRegionFlg": "寒冷地対策を行う",
+ "stuff.detail.surfaceType": "面粗度区分",
+ "stuff.detail.saltAreaFlg": "塩害地域用のアイテムを使用する",
"stuff.detail.installHeight": "設置高さ",
"stuff.detail.conType": "契約条件",
"stuff.detail.conType0": "余剰",
@@ -695,8 +703,8 @@
"stuff.detail.remarks": "メモ",
"stuff.detail.tooltip.saleStoreId": "販売代理店または販売代理店IDを1文字以上入力してください",
"stuff.detail.tooltip.surfaceType": "塩害地域の定義は各メーカーの設置マニュアルをご確認ください",
- "stuff.detail.tempSave.message0": "一時保存されました. 商品番号を取得するには、保存ボタンを押してください.",
- "stuff.detail.tempSave.message1": "一時保存されました. 物件番号を取得するには、必須項目をすべて入力してください.",
+ "stuff.detail.tempSave.message0": "一時保存されました。 物件番号を取得するには、保存ボタンを押して下さい。,",
+ "stuff.detail.tempSave.message1": "一時保存されました。物件番号を取得するには、必須項目をすべて入力してください。",
"stuff.detail.tempSave.message2": "担当者名は10桁以下で入力してください。",
"stuff.detail.tempSave.message3": "二次販売店を選択してください。",
"stuff.detail.confirm.message1": "販売店情報を変更すると、設計依頼文書番号が削除されます。変更しますか?",
@@ -707,8 +715,8 @@
"stuff.detail.planList.guide1": "1.発注は同一物件番号基準1件のみ可能です。",
"stuff.detail.planList.guide2": "2. [Excelダウンロード]は見積書図面シミュレーション結果をExcelファイルとして一度にダウンロードします。",
"stuff.detail.planList.guide3": "3. プラン情報をダブルクリックすると図面作成画面に移動します。",
- "stuff.detail.btn.delete": "物の削除",
- "stuff.detail.btn.moveList": "商品リスト",
+ "stuff.detail.btn.delete": "物件削除",
+ "stuff.detail.btn.moveList": "見積一覧",
"stuff.detail.btn.save": "保存",
"stuff.detail.btn.tempSave": "一時保存",
"stuff.detail.save": "保存しました",
@@ -730,7 +738,7 @@
"stuff.planReqPopup.gridHeader.saleStoreName": "販売代理店名",
"stuff.planReqPopup.gridHeader.title": "案件名",
"stuff.planReqPopup.gridHeader.address1": "都道府県",
- "stuff.planReqPopup.gridHeader.houseCntName": "設置家屋",
+ "stuff.planReqPopup.gridHeader.houseCntName": "設置家屋,",
"stuff.planReqPopup.gridHeader.planReqName": "依頼者名",
"stuff.planReqPopup.gridHeader.submitDt": "設計依頼提出日",
"stuff.planReqPopup.search.planReqNo": "設計依頼番号",
@@ -744,7 +752,7 @@
"stuff.planReqPopup.search.schDateGbnR": "受付日",
"stuff.planReqPopup.error.message1": "設計依頼を選択してください。",
"stuff.planReqPopup.error.message2": "販売店を選択してください。",
- "stuff.search.title": "物件状況",
+ "stuff.search.title": "物件検索",
"stuff.search.btn.register": "新規物件登録",
"stuff.search.btn.search": "照会",
"stuff.search.btn.reset": "初期化",
@@ -752,22 +760,22 @@
"stuff.search.schSaleStoreName": "販売代理店名",
"stuff.search.schAddress": "商品アドレス",
"stuff.search.schObjectName": "商品名",
- "stuff.search.schDispCompanyName": "見積もり",
- "stuff.search.schSelSaleStoreId": "販売代理店の選択",
+ "stuff.search.schDispCompanyName": "見積先",
+ "stuff.search.schSelSaleStoreId": "販売代理店選択",
"stuff.search.schReceiveUser": "担当者",
"stuff.search.period": "期間検索",
"stuff.search.schDateTypeU": "更新日",
"stuff.search.schDateTypeR": "登録日",
- "stuff.search.schTempFlgT": "一時保存物",
+ "stuff.search.schTempFlgT": "一次保存案件",
"stuff.search.schTempFlg": "含む",
"stuff.search.schTempFlg0": "除外",
- "stuff.search.schTempFlg1": "一時的なものだけを見る",
- "stuff.search.schMine": "私のものを見る",
- "stuff.search.grid.title": "商品リスト",
+ "stuff.search.schTempFlg1": "一次保存のみ表示",
+ "stuff.search.schMine": "自社案件のみ",
+ "stuff.search.grid.title": "見積一覧",
"stuff.search.grid.all": "全体",
"stuff.search.grid.selected": "選択",
"stuff.search.grid.schSortTypeR": "最近の登録日",
- "stuff.search.grid.schSortTypeU": "最近の更新日",
+ "stuff.search.grid.schSortTypeU": "最近の修正日",
"stuff.windSelectPopup.title": "風速選択",
"stuff.windSelectPopup.table.selected": "選択",
"stuff.windSelectPopup.table.windspeed": "風速",
@@ -782,16 +790,16 @@
"stuff.detail.planGridHeader.capacity": "システム容量",
"stuff.detail.planGridHeader.roofMaterialIdMulti": "屋根材",
"stuff.detail.planGridHeader.constructSpecificationMulti": "施工方法",
- "stuff.detail.planGridHeader.standTypeNo": "架台",
+ "stuff.detail.planGridHeader.supportMethodIdMulti": "架台",
"stuff.detail.planGridHeader.pcTypeNo": "パワーコンディショナー",
"stuff.detail.planGridHeader.management": "管理",
"stuff.detail.planGrid.btn1": "見積書の照会",
- "stuff.detail.planGrid.docDownload": "文書のダウンロード",
+ "stuff.detail.planGrid.docDownload": "見積書出力",
"stuff.grid.noData": "照会されたデータがありません",
"length": "長さ",
"height": "高さ",
"output": "出力",
- "slope": "傾斜",
+ "slope": "寸",
"eaves.offset": "軒の幅",
"gable.offset": "ケラバ",
"offset": "出幅",
@@ -808,7 +816,7 @@
"yosemune": "寄棟",
"valley": "谷",
"l.abandon.valley": "Lの捨て渓谷",
- "mansard": "メンサード",
+ "mansard": "マンサード,",
"wall": "壁",
"wall.merge": "壁取り",
"wall.merge.type": "壁取合(型)",
@@ -841,9 +849,10 @@
"main.storeName": "販売店名",
"main.objectNo": "物件番号",
"main.faq": "FAQ",
+ "main.archive": "各種資料ダウンロード",
"main.content.objectList.noData1": "登録された商品情報はありません。",
"main.content.objectList.noData2": "下のボタンをクリックして商品情報を登録してください。",
- "main.content.objectList": "最近の更新物件一覧",
+ "main.content.objectList": "直近の見積書一覧",
"main.content.notice": "お知らせ",
"main.content.download1": "操作マニュアル",
"main.content.download2": "屋根の説明書",
@@ -853,20 +862,21 @@
"main.popup.login.newPassword1": "新しいパスワードを入力",
"main.popup.login.newPassword2": "新しいパスワードの再入力",
"main.popup.login.placeholder": "半角10文字以内",
- "main.popup.login.guide1": "初期化されたパスワードでログインした場合、パスワードを変更しなければサイト利用が可能です.",
- "main.popup.login.guide2": "パスワードを変更しない場合は、ログイン画面に進みます.",
+ "main.popup.login.guide1": "初期化されたパスワードでログインした場合、パスワードを変更しなければサイト利用が可能です。",
+ "main.popup.login.guide2": "パスワードを変更しない場合は、ログイン画面に進みます。",
"main.popup.login.btn1": "変更",
"main.popup.login.btn2": "変更しない",
- "main.popup.login.validate1": "入力したパスワードが異なります.",
- "main.popup.login.validate2": "半角10文字以内で入力してください.",
- "main.popup.login.validate3": "パスワードを入力してください.",
- "main.popup.login.success": "パスワードが変更されました.",
+ "main.popup.login.validate1": "入力したパスワードが異なります。",
+ "main.popup.login.validate2": "半角10文字以内で入力してください。",
+ "main.popup.login.validate3": "パスワードを入力してください。",
+ "main.popup.login.success": "パスワードが変更されました。",
"common.canvas.validate.size": "サイズを入力してください。",
"surface.shape.validate.size.1to2": "①長さは②より大きい値を入れてください。",
"surface.shape.validate.size.1to3": "①長さは③より大きい値を入れてください。",
"surface.shape.validate.size.1to23": "①長さは②+③より大きい値を入れてください。",
+ "surface.shape.validate.size.1to23low": "②+③長さは①より大きい値を入れてください。",
"surface.shape.validate.size.2to3": "②長さは③より大きい値を入れてください。",
- "surface.shape.validate.size.3to2": "③長さは②より大きい値を入れてください。",
+ "surface.shape.validate.size.3to2": "③長さは②番より大きい値を入れてください。",
"surface.shape.validate.size.3to4": "③長さは④より大きい値を入れてください。",
"surface.shape.validate.size.4to3": "④長さは③より大きい値を入れてください。",
"surface.shape.validate.size.4to5": "④長さは⑤より大きい値を入れてください。",
@@ -878,51 +888,51 @@
"estimate.detail.saleStoreId": "一次販売店名",
"estimate.detail.estimateDate": "見積日",
"estimate.detail.otherSaleStoreId": "二次販売店名",
- "estimate.detail.noOtherSaleStoreId": "二次点なし",
+ "estimate.detail.noOtherSaleStoreId": "二次店なし",
"estimate.detail.receiveUser": "担当者",
"estimate.detail.objectName": "案件名",
"estimate.detail.objectRemarks": "メモ",
"estimate.detail.estimateType": "注文分類",
"estimate.detail.estimateType.yjss": "住宅PKG",
"estimate.detail.estimateType.yjod": "積上げ(YJOD)",
- "estimate.detail.roofCns": "屋根材・仕様施工",
+ "estimate.detail.roofCns": "屋根材・施工区分",
"estimate.detail.remarks": "備考",
"estimate.detail.fileFlg": "後日資料提出",
- "estimate.detail.dragFileGuide": "(※北面設置の場合、ファイル添付が必須です.)",
+ "estimate.detail.dragFileGuide": "(※北面設置の場合、ファイル添付が必須です。)",
"estimate.detail.header.fileList1": "ファイル添付",
"estimate.detail.fileList.btn": "ファイル選択",
"estimate.detail.fileList.extCheck": "画像ファイルのみ添付可能です。",
"estimate.detail.header.fileList2": "添付ファイル一覧",
"estimate.detail.fileList2.btn.return": "復元",
- "estimate.detail.header.specialEstimate": "見積もりの特定",
+ "estimate.detail.header.specialEstimate": "見積特記事項",
"estimate.detail.header.specialEstimateProductInfo": "製品情報",
"estimate.detail.sepcialEstimateProductInfo.totAmount": "数量(PCS)",
- "estimate.detail.sepcialEstimateProductInfo.totVolKw": "容量(Kw)",
- "estimate.detail.sepcialEstimateProductInfo.supplyPrice": "供給価格",
+ "estimate.detail.sepcialEstimateProductInfo.totVolKw": "容量(kW)",
+ "estimate.detail.sepcialEstimateProductInfo.supplyPrice": "見積価格",
"estimate.detail.sepcialEstimateProductInfo.vatPrice": "税(10%)",
"estimate.detail.sepcialEstimateProductInfo.totPrice": "総額",
"estimate.detail.sepcialEstimateProductInfo.pkgUnitPrice": "住宅PKG単価(W)",
- "estimate.detail.sepcialEstimateProductInfo.pkgWeight": "PKG容量(Kw)",
+ "estimate.detail.sepcialEstimateProductInfo.pkgWeight": "PKG容量(kW)",
"estimate.detail.sepcialEstimateProductInfo.pkgPrice": "PKG金額",
"estimate.detail.header.showPrice": "価格表示",
"estimate.detail.header.unitPrice": "定価",
"estimate.detail.showPrice.pricingBtn": "Pricing",
- "estimate.detail.showPrice.pricingBtn.noItemId": "Pricingが欠落しているアイテムがあります. 製品を選択してPricingを進めてください.",
+ "estimate.detail.showPrice.pricingBtn.noItemId": "Pricingが欠落しているアイテムがあります。 Pricingを進めてください。",
"estimate.detail.showPrice.description1": "製品価格OPEN",
"estimate.detail.showPrice.description2": "追加の変更品目",
"estimate.detail.showPrice.description3": "添付必須",
- "estimate.detail.showPrice.description4": "クリックして製品の特異性を確認する",
+ "estimate.detail.showPrice.description4": "クリックで製品特記事項を確認できます",
"estimate.detail.showPrice.addItem": "製品追加",
"estimate.detail.showPrice.delItem": "製品の削除",
- "estimate.detail.itemTableHeader.dispOrder": "No.",
+ "estimate.detail.itemTableHeader.dispOrder": "アイテム",
"estimate.detail.itemTableHeader.itemId": "品番",
"estimate.detail.itemTableHeader.itemNo": "型名",
"estimate.detail.itemTableHeader.amount": "数量",
"estimate.detail.itemTableHeader.unit": "単位",
"estimate.detail.itemTableHeader.salePrice": "単価",
"estimate.detail.itemTableHeader.saleTotPrice": "金額(税別)",
- "estimate.detail.docPopup.title": "文章ダウンロードオプションの設定",
- "estimate.detail.docPopup.explane": "ダウンロードする文書オプションを選択し、[文書のダウンロード]ボタンをクリックします。",
+ "estimate.detail.docPopup.title": "見積書出力オプションの設定",
+ "estimate.detail.docPopup.explane": "ダウンロードする文書オプションを選択し、[見積書出力]ボタンをクリックします。",
"estimate.detail.docPopup.schUnitPriceFlg": "ダウンロードファイル",
"estimate.detail.docPopup.schUnitPriceFlg.excelFlg0": "仕切用Excel",
"estimate.detail.docPopup.schUnitPriceFlg.excelFlg1": "定価用Excel",
@@ -938,7 +948,7 @@
"estimate.detail.docPopup.schDrawingFlg.schDrawingFlg1": "含む",
"estimate.detail.docPopup.schDrawingFlg.schDrawingFlg0": "含まない",
"estimate.detail.docPopup.close": "閉じる",
- "estimate.detail.docPopup.docDownload": "文書のダウンロード",
+ "estimate.detail.docPopup.docDownload": "見積書出力",
"estimate.detail.estimateCopyPopup.title": "見積コピー",
"estimate.detail.estimateCopyPopup.explane": "見積書をコピーする販売店を設定します。見積書は定価でコピーされます。",
"estimate.detail.estimateCopyPopup.label.saleStoreId": "一次販売店名/ID",
@@ -946,27 +956,26 @@
"estimate.detail.estimateCopyPopup.label.receiveUser": "担当者",
"estimate.detail.estimateCopyPopup.close": "閉じる",
"estimate.detail.estimateCopyPopup.copyBtn": "見積コピー",
- "estimate.detail.estimateCopyPopup.copy.alertMessage": "見積書がコピーされました。コピーした商品情報に移動します。",
+ "estimate.detail.estimateCopyPopup.copy.alertMessage": "見積書がコピーされました。コピーした見積情報に移動します。",
"estimate.detail.productFeaturesPopup.title": "製品特異事項",
"estimate.detail.productFeaturesPopup.close": "閉じる",
"estimate.detail.productFeaturesPopup.requiredStoreId": "一次販売店は必須です。",
"estimate.detail.productFeaturesPopup.requiredReceiveUser": "担当者は必須です。",
"estimate.detail.save.alertMsg": "保存されました。見積書で製品を変更すると、図面や回路には反映されません。",
- "estimate.detail.copy.alertMsg": "コピーされました.",
- "estimate.detail.save.requiredFileUpload": "ファイル添付が必須のアイテムがあります。ファイルを添付するか、後日添付をチェックしてください.",
- "estimate.detail.save.requiredNorthArrangementFileUpload": "北面にモジュールを配置した場合、北面配置許可書を必ず添付する必要があります.",
- "estimate.detail.save.requiredItem": "製品は1つ以上登録する必要があります.",
- "estimate.detail.save.requiredCharger": "担当者は必須です.",
- "estimate.detail.save.requiredObjectName": "案件名は必須です.",
- "estimate.detail.save.requiredPkgAsp": "住宅pkg単価は0より大きい値を入力してください.",
- "estimate.detail.save.requiredEstimateDate": "見積日は必須です.",
- "estimate.detail.save.requiredItemId": "製品を選択してください.",
- "estimate.detail.save.requiredAmount": "数量は0より大きい値を入力してください.",
- "estimate.detail.save.requiredSalePrice": "単価は0より大きい値を入力してください.",
- "estimate.detail.save.requiredEstimateType": "注文分類を選択してください.",
- "estimate.detail.reset.alertMsg": "初期化されました.",
+ "estimate.detail.copy.alertMsg": "コピーされました。",
+ "estimate.detail.save.requiredFileUpload": "ファイル添付が必須のアイテムがあります。ファイルを添付するか、後日添付をチェックしてください。",
+ "estimate.detail.save.requiredNorthArrangementFileUpload": "北面にモジュールを配置した場合、北面配置許可書を必ず添付しなければなりません。",
+ "estimate.detail.save.requiredItem": "製品は1つ以上登録する必要があります。",
+ "estimate.detail.save.requiredCharger": "担当者は必須です。",
+ "estimate.detail.save.requiredObjectName": "案件名は必須です。",
+ "estimate.detail.save.requiredPkgAsp": "住宅PKG単価は0より大きい値を入力してください。",
+ "estimate.detail.save.requiredEstimateDate": "見積日は必須です。",
+ "estimate.detail.save.requiredItemId": "製品を選択してください。",
+ "estimate.detail.save.requiredAmount": "数量は0より大きい値を入力してください。",
+ "estimate.detail.save.requiredSalePrice": "単価は0より大きい値を入力してください。",
+ "estimate.detail.reset.alertMsg": "初期化されました。",
"estimate.detail.reset.confirmMsg": "保存した見積情報が初期化され、最近保存された図面情報が反映されます。本当に初期化しますか?",
- "estimate.detail.lock.alertMsg": "見積もりを[ロック]すると変更できません。
見積もりを修正するには、ロックを解除してください.",
+ "estimate.detail.lock.alertMsg": "見積もりを[ロック]すると変更できません。
見積もりを修正するには、ロックを解除してください。",
"estimate.detail.unlock.alertMsg": "[ロック解除]すると、見積書を編集できます。
解除しますか?",
"estimate.detail.unlock.confirmBtnName": "解放",
"estimate.detail.alert.delFile": "添付ファイルを完全に削除するには、[保存]ボタンをクリックしてください。",
@@ -1008,16 +1017,22 @@
"module.place.select.one.module": "モジュールは1つだけ選択してください。",
"batch.canvas.delete.all": "配置面の内容をすべて削除しますか?",
"module.not.found": "インストールモジュールを選択してください。",
+ "module.circuit.minimun.error": "回路番号は1以上の数値を入力してください。",
+ "module.already.exist.error": "回路番号が同じで異なるパワーコンディショナのモジュールがあります。 別の回路番号を設定してください。",
"construction.length.difference": "屋根面工法をすべて選択してください。",
"menu.validation.canvas.roof": "パネルを配置するには、屋根面を入力する必要があります。",
"batch.object.outside.roof": "オブジェクトは屋根に設置する必要があります。",
"batch.object.notinstall.cross": "オブジェクトは重複してインストールできません。",
- "module.not.batch.north": "북쪽에는 모듈을 배치할 수 없습니다.",
- "module.trestleDetail.not.exist": "가대 상세 정보가 없습니다.",
- "max.select": "최대 {0}개까지 선택할 수 있습니다.(JA)",
- "not.allocation.exist.module": "할당하지 않은 모듈이 있습니다.(JA)",
- "roof.is.not.selected": "지붕을 선택해주세요.(JA)",
- "module.delete.confirm": "パネルを削除して面入力に戻ります。正しいですか?\nはい]を選択すると削除し、面入力に戻ります。\nいいえ」を選択すると、削除せずに現在の状態を維持します。",
- "length.direction.is.required": "길이와 방향을 입력하세요.(JA)",
- "canvas.infomation.text": "数字は [半角] 入力のみ可能です。"
+ "module.not.batch.north": "北面にモジュールを配置することはできません。",
+ "module.trestleDetail.not.exist": "架台の詳細情報がありません。",
+ "max.select": "最大{0}個まで選択できます。",
+ "module.delete.confirm": "配置されたモジュール パネルを削除し、面入力に戻ります。よろしいですか?",
+ "not.allocation.exist.module": "回路を割り当てていないモジュールがあります。",
+ "roof.is.not.selected": "屋根の選択をお願いします。",
+ "length.direction.is.required": "長さと方向を入力します。",
+ "canvas.infomation.text": "数字は [半角] 入力のみ可能です。",
+ "roof.exceed.count": "屋根材は4つまで選択可能です。",
+ "outerLine.property.fix": "外壁線の属性設定 を完了しますか?",
+ "outerLine.property.close": "外壁線の属性設定 を終了しますか?",
+ "want.to.complete.auxiliary.creation": "보補助線の作成を完了しますか?"
}
diff --git a/src/locales/ko.json b/src/locales/ko.json
index d0bead71..4c051305 100644
--- a/src/locales/ko.json
+++ b/src/locales/ko.json
@@ -9,7 +9,7 @@
"header.menus.community": "커뮤니티",
"header.menus.community.notice": "공지사항",
"header.menus.community.faq": "FAQ",
- "header.menus.community.archive": "문서다운로드",
+ "header.menus.community.archive": "각종 자료 다운로드",
"header.logout": "로그아웃",
"header.go": "이동",
"header.online.warranty.system": "온라인보증시스템",
@@ -90,7 +90,7 @@
"modal.module.basic.setting.orientation.setting.info": "※시뮬레이션 계산용 방위를 지정합니다. 남쪽의 방위를 설정해주세요.",
"modal.module.basic.setting.orientation.setting.angle.passivity": "각도를 직접 입력",
"modal.module.basic.setting.module.roof.material": "지붕재",
- "modal.module.basic.setting.module.trestle.maker": "가대메이거",
+ "modal.module.basic.setting.module.trestle.maker": "가대메이커",
"modal.module.basic.setting.module.rafter.margin": "서까래 간격",
"modal.module.basic.setting.module.construction.method": "공법",
"modal.module.basic.setting.module.under.roof": "지붕밑바탕",
@@ -110,7 +110,7 @@
"modal.module.basic.setting.module.blind.metal.fitting": "적설방지금구설치",
"modal.module.basic.setting.module.select": "모듈/가대 선택",
"modal.module.basic.setting.module.placement": "모듈 배치",
- "modal.module.basic.setting.module.placement.select.fitting.type": "설치형태를 선택해주세요.",
+ "modal.module.basic.setting.module.placement.select.fitting.type": "설치형태를 선택합니다.",
"modal.module.basic.setting.module.placement.waterfowl.arrangement": "물떼새 배치",
"modal.module.basic.setting.module.placement.do": "한다",
"modal.module.basic.setting.module.placement.do.not": "하지 않는다",
@@ -148,7 +148,7 @@
"modal.circuit.trestle.setting.circuit.allocation.auto": "자동회로 할당",
"modal.circuit.trestle.setting.circuit.allocation.passivity": "수동회로 할당",
"modal.circuit.trestle.setting.circuit.allocation.passivity.circuit": "회로",
- "modal.circuit.trestle.setting.circuit.allocation.passivity.series": "시리즈",
+ "modal.circuit.trestle.setting.circuit.allocation.passivity.series": "PCS시리즈",
"modal.circuit.trestle.setting.circuit.allocation.passivity.name": "명칭",
"modal.circuit.trestle.setting.circuit.allocation.passivity.info": "동일한 회로의 모듈을 선택 상태로 만든 후 [번호 확정] 버튼을 누르면 번호가 할당됩니다.",
"modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional": "선택된 파워컨디셔너",
@@ -174,6 +174,7 @@
"modal.roof.alloc.info": "※ 배치면 초기설정에서 저장한 [기본 지붕재]를 변경하거나 지붕재를 추가하여 할당할 수 있습니다.",
"modal.roof.alloc.default.roof.material": "기본 지붕재",
"modal.roof.alloc.select.roof.material": "지붕재 선택",
+ "modal.roof.alloc.add.roof.material": "지붕재 추가",
"modal.roof.alloc.select.parallel": "병렬식",
"modal.roof.alloc.select.stairs": "계단식",
"modal.roof.alloc.apply": "선택한 지붕재로 할당",
@@ -269,6 +270,10 @@
"modal.canvas.setting.wallline.properties.setting.info": "※ 속성을 변경할 외벽선을 선택하고 처마로 설정 또는 케라바로 설정\n 버튼을 클릭하여 설정값을 적용하십시오.\n",
"modal.canvas.setting.wallline.properties.setting.eaves": "처마로 설정",
"modal.canvas.setting.wallline.properties.setting.edge": "케라바로 설정",
+ "modal.canvas.setting.wallline.properties.setting.ridge": "용마루로 설정",
+ "modal.canvas.setting.roofline.properties.setting": "지붕선 속성 설정",
+ "modal.canvas.setting.roofline.properties.setting.info": "※ 속성을 변경할 지붕선을 선택하고 처마로 설정 또는 케라바로 설정\n 버튼을 클릭하여 설정값을 적용하십시오.\n",
+ "modal.canvas.setting.roofline.properties.setting.not.setting": "설정하지 않은 라인이 존재합니다.",
"modal.eaves.gable.edit": "처마/케라바 변경",
"modal.eaves.gable.edit.basic": "통상",
"modal.eaves.gable.edit.wall.merge.info": "하옥 등 벽에 접하는 지붕을 작성합니다.",
@@ -288,9 +293,11 @@
"modal.object.setting.height": "세로길이",
"modal.object.setting.area.cross": "영역교차",
"modal.object.setting.size.setting": "사이즈설정",
- "modal.object.setting.agreement.depth": "동의길이 깊이",
- "modal.object.setting.offset.depth": "출폭(깊이)",
- "modal.object.setting.offset.width": "출폭(폭)",
+ "modal.object.setting.agreement.depth": "동의 길이",
+ "modal.object.setting.offset.depth": "동의 출폭",
+ "modal.object.setting.size.width": "너비",
+ "modal.object.setting.offset.width": "너비의 출폭",
+ "modal.object.setting.offset.slope": "경사",
"modal.object.setting.direction.select": "방향 선택",
"modal.placement.surface.setting.info": "ⓘ ①의 길이 입력 후 대각선 길이를 입력하면 ②의 길이를 자동 계산합니다.",
"modal.placement.surface.setting.diagonal.length": "대각선 길이",
@@ -372,7 +379,7 @@
"contextmenu.row.remove": "단 삭제",
"modal.row.remove": "단 삭제",
"modal.row.remove.info": "삭제 단을 어떻게 하시겠습니까?",
- "modal.row.remove.type.up": "위족으로 줄이다",
+ "modal.row.remove.type.up": "위쪽으로 줄이다",
"modal.row.remove.type.down": "아래쪽으로 줄이다",
"modal.row.remove.type.side": "양쪽으로 줄이다",
"modal.row.remove.type.none": "줄이지 않는다",
@@ -421,6 +428,7 @@
"modal.module.circuit.number.edit": "모듈 일괄 회로 번호 변경",
"modal.module.circuit.number.edit.info": "회로 번호를 입력해주세요.",
"modal.module.circuit.number": "회로 번호",
+ "modal.module.pcs.error1": "병설용 PCS는 단독으로 선택할 수 없습니다.",
"modal.module.can.not.edit": "회로 구성을 완료한 모듈은 변경할 수 없습니다.",
"modal.line.property.change": "변경할 속성을 선택해 주세요.",
"modal.line.property.change.unselect": "변경할 라인을 선택해 주세요.",
@@ -549,7 +557,7 @@
"board.notice.sub.title": "공지사항 목록",
"board.faq.title": "FAQ",
"board.faq.sub.title": "FAQ 목록",
- "board.archive.title": "자료 다운로드",
+ "board.archive.title": "각종 자료 다운로드",
"board.archive.sub.title": "문서 목록",
"board.list.header.rownum": "번호",
"board.list.header.title": "제목",
@@ -612,9 +620,9 @@
"join.sub1.addr": "주소",
"join.sub1.addr_placeholder": "전각50자이내",
"join.sub1.telNo": "전화번호",
- "join.sub1.telNo_placeholder": "00-0000-0000",
+ "join.sub1.telNo_placeholder": "00 0000 0000",
"join.sub1.fax": "FAX 번호",
- "join.sub1.fax_placeholder": "00-0000-0000",
+ "join.sub1.fax_placeholder": "00 0000 0000",
"join.sub1.bizNo": "법인번호",
"join.sub2.title": "담당자 정보",
"join.sub2.userNm": "담당자명",
@@ -622,9 +630,9 @@
"join.sub2.userId": "신청 ID",
"join.sub2.email": "이메일 주소",
"join.sub2.telNo": "전화번호",
- "join.sub2.telNo_placeholder": "00-0000-0000",
+ "join.sub2.telNo_placeholder": "00 0000 0000",
"join.sub2.fax": "FAX 번호",
- "join.sub2.fax_placeholder": "00-0000-0000",
+ "join.sub2.fax_placeholder": "00 0000 0000",
"join.sub2.category": "부서명",
"join.btn.login_page": "로그인 화면으로 이동",
"join.btn.approval_request": "ID 승인요청",
@@ -658,7 +666,7 @@
"stuff.planReqPopup.title": "설계의뢰 불러오기",
"stuff.temp.subTitle": "물건정보",
"stuff.temp.subTitle2": "도면작성",
- "stuff.detail.header.notExistObjectNo": "존재하지 않는 물건입니다.",
+ "stuff.detail.header.notExistObjectNo": "존재하지 않는 물건번호 입니다.",
"stuff.detail.header.successCopy": "물건번호가 복사되었습니다.",
"stuff.detail.header.failCopy": "물건번호 복사에 실패했습니다.",
"stuff.detail.header.objectNo": "물건번호",
@@ -730,7 +738,7 @@
"stuff.planReqPopup.gridHeader.saleStoreName": "판매대리점명",
"stuff.planReqPopup.gridHeader.title": "안건명",
"stuff.planReqPopup.gridHeader.address1": "도도부현",
- "stuff.planReqPopup.gridHeader.houseCntName": "설치가옥수",
+ "stuff.planReqPopup.gridHeader.houseCntName": "설치가옥수, ",
"stuff.planReqPopup.gridHeader.planReqName": "의뢰자명",
"stuff.planReqPopup.gridHeader.submitDt": "설계의뢰 제출일",
"stuff.planReqPopup.search.planReqNo": "설계의뢰번호",
@@ -782,7 +790,7 @@
"stuff.detail.planGridHeader.capacity": "시스템용량",
"stuff.detail.planGridHeader.roofMaterialIdMulti": "지붕재",
"stuff.detail.planGridHeader.constructSpecificationMulti": "시공방법",
- "stuff.detail.planGridHeader.standTypeNo": "가대",
+ "stuff.detail.planGridHeader.supportMethodIdMulti": "가대",
"stuff.detail.planGridHeader.pcTypeNo": "파워컨디셔너",
"stuff.detail.planGridHeader.management": "관리",
"stuff.detail.planGrid.btn1": "견적서 조회",
@@ -808,7 +816,7 @@
"yosemune": "요세무네",
"valley": "골짜기",
"l.abandon.valley": "L의 버림 계곡",
- "mansard": "멘사드",
+ "mansard": "멘사드,",
"wall": "벽",
"wall.merge": "벽취합",
"wall.merge.type": "벽취합(형)",
@@ -841,6 +849,7 @@
"main.storeName": "판매점명",
"main.objectNo": "물건번호",
"main.faq": "FAQ",
+ "main.archive": "각종 자료 다운로드",
"main.content.objectList.noData1": "등록된 물건정보가 없습니다.",
"main.content.objectList.noData2": "아래 버튼을 클릭하여 물건정보를 등록하십시오.",
"main.content.objectList": "최근 갱신 물건목록",
@@ -892,7 +901,7 @@
"estimate.detail.dragFileGuide": "(※ 북면설치인 경우, 파일 첨부가 필수입니다.)",
"estimate.detail.header.fileList1": "파일첨부",
"estimate.detail.fileList.btn": "파일선택",
- "estimate.detail.fileList.extCheck": "이미지 파일만 첨부 가능합니다.",
+ "estimate.detail.fileList.extCheck": "이미지, PDF, 엑셀 파일만 첨부 가능합니다.",
"estimate.detail.header.fileList2": "첨부파일 목록",
"estimate.detail.fileList2.btn.return": "복원",
"estimate.detail.header.specialEstimate": "견적특이사항",
@@ -915,7 +924,7 @@
"estimate.detail.showPrice.description4": "클릭하여 제품 특이사항 확인",
"estimate.detail.showPrice.addItem": "제품추가",
"estimate.detail.showPrice.delItem": "제품삭제",
- "estimate.detail.itemTableHeader.dispOrder": "No.",
+ "estimate.detail.itemTableHeader.dispOrder": "Item",
"estimate.detail.itemTableHeader.itemId": "품번",
"estimate.detail.itemTableHeader.itemNo": "형명",
"estimate.detail.itemTableHeader.amount": "수량",
@@ -932,7 +941,7 @@
"estimate.detail.docPopup.schDisplayFlg": "견적제출서 표시명",
"estimate.detail.docPopup.schDisplayFlg.schDisplayFlg0": "판매점명",
"estimate.detail.docPopup.schDisplayFlg.schDisplayFlg1": "안건명",
- "estimate.detail.docPopup.schWeightFlg": "가대 중량표 포함",
+ "estimate.detail.docPopup.schWeightFlg": "가대중량표 포함",
"estimate.detail.docPopup.schWeightFlg.schWeightFlg1": "포함",
"estimate.detail.docPopup.schWeightFlg.schWeightFlg0": "미포함",
"estimate.detail.docPopup.schDrawingFlg": "도면/시뮬레이션 파일 포함",
@@ -964,7 +973,6 @@
"estimate.detail.save.requiredItemId": "제품을 선택해주세요.",
"estimate.detail.save.requiredAmount": "수량은 0보다 큰값을 입력해주세요.",
"estimate.detail.save.requiredSalePrice": "단가는 0보다 큰값을 입력해주세요.",
- "estimate.detail.save.requiredEstimateType": "주문분류를 선택해주세요.",
"estimate.detail.reset.alertMsg": "초기화 되었습니다.",
"estimate.detail.reset.confirmMsg": "수기 변경(저장)한 견적 정보가 초기화되고 최근 저장된 도면정보가 반영됩니다. 정말로 초기화하시겠습니까?",
"estimate.detail.lock.alertMsg": "견적서를 [잠금]하면 수정할 수 없습니다.
견적서를 수정하려면 잠금해제를 하십시오.",
@@ -1007,18 +1015,24 @@
"module.place.no.surface": "선택된 모듈 설치면이 없습니다.",
"module.place.select.module": "모듈을 선택해주세요.",
"module.place.select.one.module": "모듈은 하나만 선택해주세요.",
- "batch.canvas.delete.all": "배치면 내용을 전부 삭제하시겠습니까?",
+ "batch.canvas.delete.all": "배치면 내용을 모두 삭제하시겠습니까?",
"module.not.found": "모듈을 선택하세요.",
- "construction.length.difference": "지붕면 공법을 전부 선택해주세요.",
+ "module.circuit.minimun.error": "회로번호는 1 이상입력해주세요.",
+ "module.already.exist.error": "회로번호가 같은 다른 파워 컨디셔너 모듈이 있습니다. 다른 회로번호를 설정하십시오.",
+ "construction.length.difference": "지붕면 공법을 모두 선택하십시오.",
"menu.validation.canvas.roof": "패널을 배치하려면 지붕면을 입력해야 합니다.",
"batch.object.outside.roof": "오브젝트는 지붕내에 설치해야 합니다.",
- "batch.object.notinstall.cross": "오브젝트는 겹쳐서 설치 할 수 없습니다.",
+ "batch.object.notinstall.cross": "오브젝트는 겹쳐서 설치할 수 없습니다.",
"module.not.batch.north": "북쪽에는 모듈을 배치할 수 없습니다.",
"module.trestleDetail.not.exist": "가대 상세 정보가 없습니다.",
"max.select": "최대 {0}개까지 선택할 수 있습니다.",
- "module.delete.confirm": "패널을 삭제하고 면입력으로 돌아갑니다. 맞습니까?\n[예]를 선택하면 삭제하고, 면 입력으로 돌아갑니다.\n[아니오]를 선택하면 삭제하지 않고 현재 상태를 유지합니다.",
- "not.allocation.exist.module": "할당하지 않은 모듈이 있습니다.",
+ "module.delete.confirm": "배치된 모듈패널을 삭제하고 면입력으로 돌아갑니다. 맞습니까?",
+ "not.allocation.exist.module": "회로를 할당하지 않은 모듈이 있습니다.",
"roof.is.not.selected": "지붕을 선택해주세요.",
"length.direction.is.required": "길이와 방향을 입력하세요.",
- "canvas.infomation.text": "숫자는 [반각]입력만 가능합니다."
+ "canvas.infomation.text": "숫자는 [반각] 입력만 가능합니다.",
+ "roof.exceed.count": "지붕재는 4개까지 선택 가능합니다.",
+ "outerLine.property.fix": "외벽선 속성 설정을 완료하시겠습니까?",
+ "outerLine.property.close": "외벽선 속성 설정을 종료하시겠습니까?",
+ "want.to.complete.auxiliary.creation": "보조선 작성을 완료하시겠습니까?"
}
diff --git a/src/middleware.js b/src/middleware.js
index c9e6811c..80b747ae 100644
--- a/src/middleware.js
+++ b/src/middleware.js
@@ -1,14 +1,3 @@
-// import { createI18nMiddleware } from 'next-international/middleware'
-
-// const I18nMiddleware = createI18nMiddleware({
-// locales: ['ko', 'ja'],
-// defaultLocale: 'ko',
-// })
-
-// export function middleware(request) {
-// return I18nMiddleware(request)
-// }
-
export const config = {
matcher: ['/((?!api|static|.*\\..*|_next|favicon.ico|robots.txt).*)'],
}
diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js
index 772e55be..ddeed03d 100644
--- a/src/store/canvasAtom.js
+++ b/src/store/canvasAtom.js
@@ -43,7 +43,7 @@ export const fontSizeState = atom({
export const canvasSizeState = atom({
key: 'canvasSize',
default: {
- vertical: 1000,
+ vertical: 1600,
horizontal: 1600,
},
})
diff --git a/src/store/circuitTrestleAtom.js b/src/store/circuitTrestleAtom.js
index d1477e13..b513a16c 100644
--- a/src/store/circuitTrestleAtom.js
+++ b/src/store/circuitTrestleAtom.js
@@ -36,8 +36,8 @@ export const moduleStatisticsState = atom({
key: 'moduleStatisticsState',
default: {
header: [
- { name: '지붕면', prop: 'name' },
- { name: `발전량(kW)`, prop: 'amount' },
+ { name: '屋根面', prop: 'name' },
+ { name: `合計(kW)`, prop: 'amount' },
],
rows: [],
footer: [
diff --git a/src/store/menuAtom.js b/src/store/menuAtom.js
index 759df0fd..6cfa656c 100644
--- a/src/store/menuAtom.js
+++ b/src/store/menuAtom.js
@@ -6,32 +6,33 @@ export const menuNumberState = atom({
default: null,
})
-export const menuTypeState = atom({
- key: 'menuTypeState',
+export const selectedMenuState = atom({
+ key: 'selectedMenuState',
default: null,
})
export const menusState = atom({
key: 'menusState',
default: [
- { index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING },
+ { type: 'drawing', name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING }, //. 물건정보
{
- index: 1,
+ type: 'placement', // 배치면 초기설정
name: 'plan.menu.placement.surface.initial.setting',
icon: 'con01',
title: MENU.INITIAL_CANVAS_SETTING,
},
- { index: 2, name: 'plan.menu.roof.cover', icon: 'con02', title: MENU.ROOF_COVERING.DEFAULT },
- { index: 3, name: 'plan.menu.placement.surface', icon: 'con03', title: MENU.BATCH_CANVAS.DEFAULT },
- { index: 4, name: 'plan.menu.module.circuit.setting', icon: 'con04', title: MENU.MODULE_CIRCUIT_SETTING.DEFAULT },
- { index: 5, name: 'plan.menu.estimate', icon: 'con06', title: MENU.ESTIMATE.DEFAULT },
- { index: 6, name: 'plan.menu.simulation', icon: 'con05', title: MENU.POWER_GENERATION_SIMULATION.DEFAULT },
+ { type: 'outline', name: 'plan.menu.roof.cover', icon: 'con02', title: MENU.ROOF_COVERING.DEFAULT },
+ { type: 'surface', name: 'plan.menu.placement.surface', icon: 'con03', title: MENU.BATCH_CANVAS.DEFAULT },
+ { type: 'module', name: 'plan.menu.module.circuit.setting', icon: 'con04', title: MENU.MODULE_CIRCUIT_SETTING.DEFAULT },
+ { type: 'estimate', name: 'plan.menu.estimate', icon: 'con06', title: MENU.ESTIMATE.DEFAULT },
+ { type: 'simulation', name: 'plan.menu.simulation', icon: 'con05', title: MENU.POWER_GENERATION_SIMULATION.DEFAULT },
],
})
export const subMenusState = atom({
key: 'subMenusState',
default: {
+ placement: [], // 배치면 초기 설정
outline: [
// 지붕덮개
{ id: 0, name: 'plan.menu.roof.cover.outline.drawing', menu: MENU.ROOF_COVERING.EXTERIOR_WALL_LINE },
diff --git a/src/store/popupAtom.js b/src/store/popupAtom.js
index 8cba0bdc..72acaee5 100644
--- a/src/store/popupAtom.js
+++ b/src/store/popupAtom.js
@@ -27,3 +27,15 @@ export const contextPopupPositionState = atom({
},
dangerouslyAllowMutability: true,
})
+
+/** 팝업 스피너 상태 */
+export const popSpinnerState = atom({
+ key: 'popSpinnerStore',
+ default: false,
+})
+
+/** 프로미스 팝업 상태 - 테스트용(삭제 예정) */
+export const promisePopupState = atom({
+ key: 'promisePopupStore',
+ default: false,
+})
diff --git a/src/store/settingAtom.js b/src/store/settingAtom.js
index 0addc5c8..012e5bdc 100644
--- a/src/store/settingAtom.js
+++ b/src/store/settingAtom.js
@@ -1,8 +1,12 @@
import { atom, selector } from 'recoil'
+/**
+ * 디스플레이 설정
+ */
export const settingModalFirstOptionsState = atom({
key: 'settingModalFirstOptions',
default: {
+ /** 디스플레이 설정 */
option1: [
{ id: 1, column: 'allocDisplay', name: 'modal.canvas.setting.first.option.alloc', selected: true },
{ id: 2, column: 'outlineDisplay', name: 'modal.canvas.setting.first.option.outline', selected: true },
@@ -15,6 +19,7 @@ export const settingModalFirstOptionsState = atom({
{ id: 9, column: 'imageDisplay', name: 'modal.canvas.setting.first.option.image', selected: false },
{ id: 10, column: 'totalDisplay', name: 'modal.canvas.setting.first.option.total', selected: true },
],
+ /** 치수 표시 */
dimensionDisplay: [
{
id: 1,
@@ -25,6 +30,7 @@ export const settingModalFirstOptionsState = atom({
{ id: 2, column: 'realDimension', name: 'modal.canvas.setting.first.option.real.dimension', selected: false },
{ id: 3, column: 'noneDimension', name: 'modal.canvas.setting.first.option.none.dimension', selected: false },
],
+ /** 화면 표시 */
option2: [
{ id: 1, column: 'onlyBorder', name: 'modal.canvas.setting.first.option.border', selected: true },
{ id: 2, column: 'lineHatch', name: 'modal.canvas.setting.first.option.line', selected: false },
@@ -34,15 +40,20 @@ export const settingModalFirstOptionsState = atom({
dangerouslyAllowMutability: true,
})
+/**
+ * 디스플레이 설정 - 문자 표시
+ */
export const settingModalSecondOptionsState = atom({
key: 'settingModalSecondOptions',
default: {
+ /** 문자 표시 */
option3: [
{ id: 1, name: 'modal.canvas.setting.font.plan.edit.word' },
{ id: 2, name: 'modal.canvas.setting.font.plan.edit.flow' },
{ id: 3, name: 'modal.canvas.setting.font.plan.edit.dimension' },
{ id: 4, name: 'modal.canvas.setting.font.plan.edit.circuit.num' },
],
+ /** 흡수범위 */
option4: [
{
id: 1,
@@ -77,6 +88,9 @@ export const settingModalSecondOptionsState = atom({
dangerouslyAllowMutability: true,
})
+/**
+ * 디스플레이 설정 - 그리드 표시
+ */
export const settingModalGridOptionsState = atom({
key: 'settingModalGridOptions',
default: [
@@ -88,7 +102,9 @@ export const settingModalGridOptionsState = atom({
dangerouslyAllowMutability: true,
})
-// 디스플레이 설정 - 할당 표시
+/**
+ * 디스플레이 설정 - 할당 표시
+ */
export const allocDisplaySelector = selector({
key: 'allocDisplaySelector',
get: ({ get }) => {
@@ -97,7 +113,9 @@ export const allocDisplaySelector = selector({
},
})
-// 디스플레이 설정 - 외벽선 표시
+/**
+ * 디스플레이 설정 - 외벽선 표시
+ */
export const outlineDisplaySelector = selector({
key: 'outlineDisplaySelector',
get: ({ get }) => {
@@ -106,7 +124,9 @@ export const outlineDisplaySelector = selector({
},
})
-// 디스플레이 설정 - 그리드 표시
+/**
+ * 디스플레이 설정 - 그리드 표시
+ */
export const gridDisplaySelector = selector({
key: 'gridDisplaySelector',
get: ({ get }) => {
@@ -115,7 +135,9 @@ export const gridDisplaySelector = selector({
},
})
-// 디스플레이 설정 - 지붕선 표시
+/**
+ * 디스플레이 설정 - 지붕선 표시
+ */
export const roofLineDisplaySelector = selector({
key: 'lineDisplaySelector',
get: ({ get }) => {
@@ -124,7 +146,9 @@ export const roofLineDisplaySelector = selector({
},
})
-// 디스플레이 설정 - 문자 표시
+/**
+ * 디스플레이 설정 - 문자 표시
+ */
export const wordDisplaySelector = selector({
key: 'wordDisplaySelector',
get: ({ get }) => {
@@ -133,7 +157,9 @@ export const wordDisplaySelector = selector({
},
})
-// 디스플레이 설정 - 회로번호 표시
+/**
+ * 디스플레이 설정 - 회로번호 표시
+ */
export const circuitNumDisplaySelector = selector({
key: 'circuitNumDisplaySelector',
get: ({ get }) => {
@@ -142,7 +168,9 @@ export const circuitNumDisplaySelector = selector({
},
})
-// 디스플레이 설정 - 흐름 방향 표시
+/**
+ * 디스플레이 설정 - 흐름 방향 표시
+ */
export const flowDisplaySelector = selector({
key: 'flowDisplaySelector',
get: ({ get }) => {
@@ -151,7 +179,9 @@ export const flowDisplaySelector = selector({
},
})
-// 디스플레이 설정 - 가대 표시
+/**
+ * 디스플레이 설정 - 가대 표시
+ */
export const trestleDisplaySelector = selector({
key: 'trestleDisplaySelector',
get: ({ get }) => {
@@ -160,7 +190,9 @@ export const trestleDisplaySelector = selector({
},
})
-// 디스플레이 설정 - 이미지 표시
+/**
+ * 디스플레이 설정 - 이미지 표시
+ */
export const imageDisplaySelector = selector({
key: 'imageDisplaySelector',
get: ({ get }) => {
@@ -169,7 +201,9 @@ export const imageDisplaySelector = selector({
},
})
-// 디스플레이 설정 - 집계표 표시
+/**
+ * 디스플레이 설정 - 집계표 표시
+ */
export const totalDisplaySelector = selector({
key: 'totalDisplaySelector',
get: ({ get }) => {
@@ -178,7 +212,9 @@ export const totalDisplaySelector = selector({
},
})
-// 디스플레이 설정 - 치수 표시
+/**
+ * 디스플레이 설정 - 치수 표시
+ */
export const corridorDimensionSelector = selector({
key: 'corridorDimensionSelector',
get: ({ get }) => {
@@ -188,7 +224,9 @@ export const corridorDimensionSelector = selector({
dangerouslyAllowMutability: true,
})
-// 디스플레이 설정 - 화면 표시
+/**
+ * 디스플레이 설정 - 화면 표시
+ */
export const roofDisplaySelector = selector({
key: 'roofDisplaySelector',
get: ({ get }) => {
@@ -198,29 +236,39 @@ export const roofDisplaySelector = selector({
dangerouslyAllowMutability: true,
})
+/**
+ * basicSetting 설정
+ */
export const basicSettingState = atom({
key: 'basicSettingState',
default: {
- roofSizeSet: 1,
- roofAngleSet: 'slope',
- selectedRoofMaterial: {}, // 선택된 지붕재
- roofs: [], // 지붕면 할당에서 추가된 지붕재 목록
+ roofSizeSet: 1 /** 지붕크기 */,
+ roofAngleSet: 'slope' /** 지붕각도 */,
+ selectedRoofMaterial: {} /** 선택된 지붕재 */,
+ roofs: [] /** 지붕면 할당에서 추가된 지붕재 목록 */,
},
dangerouslyAllowMutability: true,
})
+/**
+ * 지붕면 할당에서 추가된 지붕재 목록
+ */
export const addedRoofsState = atom({
key: 'addedRoofsState',
default: [],
})
-// db에 등록된 지붕재 목록
+/**
+ * db에 등록된 지붕재 목록
+ */
export const roofMaterialsAtom = atom({
key: 'roofMaterialState',
default: [],
})
-//현재 선택된 지붕재
+/**
+ * 현재 선택된 지붕재
+ */
export const selectedRoofMaterialSelector = selector({
key: 'selectedRoofMaterialSelector',
get: ({ get }) => {
@@ -228,7 +276,9 @@ export const selectedRoofMaterialSelector = selector({
},
})
-// QSelectBox에서 사용할 지붕재 목록
+/**
+ * QSelectBox에서 사용할 지붕재 목록
+ */
export const roofMaterialsSelector = selector({
key: 'roofMaterialsSelector',
get: ({ get }) => {
@@ -245,6 +295,9 @@ export const correntObjectNoState = atom({
default: '',
})
+/**
+ * 지붕재 목록 조회 여부
+ */
export const fetchRoofMaterialsState = atom({
key: 'fetchRoofMaterialsState',
default: false,
diff --git a/src/styles/_canvasside.scss b/src/styles/_canvasside.scss
index b49087ed..9cc78a72 100644
--- a/src/styles/_canvasside.scss
+++ b/src/styles/_canvasside.scss
@@ -86,6 +86,7 @@
border: 1px solid #E9E9E9;
background: #FFF;
box-shadow: 0px 6px 14px 0px rgba(0, 0, 0, 0.05);
+ z-index: 110000;
ul{
padding: 17px 0;
border-bottom: 1px solid #E9E9E9;
diff --git a/src/styles/_modal.scss b/src/styles/_modal.scss
index b6e2d322..65b104b7 100644
--- a/src/styles/_modal.scss
+++ b/src/styles/_modal.scss
@@ -769,6 +769,13 @@ $alert-color: #101010;
background-color: #365f6e;
}
}
+ &.gray{
+ background-color: #535353;
+ border: 1px solid #9e9e9e;
+ &:hover{
+ background-color: #6b6b6b;
+ }
+ }
}
}
}
@@ -897,6 +904,8 @@ $alert-color: #101010;
.allocation-edit{
display: flex;
align-items: center;
+ justify-content: center;
+ width: 100%;
height: 30px;
padding: 0 10px;
margin-left: 5px;
@@ -905,6 +914,7 @@ $alert-color: #101010;
font-weight: $pop-normal-weight;
border: 1px solid #484848;
background-color: #323234;
+ transition: background-color .13s ease-in-out;
i{
display: block;
width: 12px;
@@ -913,6 +923,9 @@ $alert-color: #101010;
background: url(../../public/static/images/canvas/allocation_edit.svg)no-repeat center;
background-size: cover;
}
+ &:hover{
+ background-color: #464545;
+ }
}
}
@@ -988,6 +1001,26 @@ $alert-color: #101010;
}
}
}
+ &:disabled{
+ color: $pop-color;
+ border: 1px solid #646464;
+ background-color: transparent;
+ opacity: 0.5;
+ &.act,
+ &:hover{
+ color: $pop-color;
+ border: 1px solid #646464;
+ background-color: transparent;
+ i{
+ &.allocation01{
+ background-image: url(../../public/static/images/canvas/allocation_icon01_white.svg);
+ }
+ &.allocation02{
+ background-image: url(../../public/static/images/canvas/allocation_icon02_white.svg);
+ }
+ }
+ }
+ }
}
}
@@ -1205,7 +1238,6 @@ $alert-color: #101010;
.object-size-wrap{
display: flex;
min-height: 206px;
- gap: 24px;
margin-top: 14px;
.object-size-img{
position: relative;
@@ -1219,6 +1251,18 @@ $alert-color: #101010;
transform: translate(-50%, -50%);
}
}
+ .object-size-input{
+ margin-left: auto;
+ .eaves-keraba-th{
+ position: relative;
+ .object-input-num{
+ position: absolute;
+ top: 7px;
+ left: -20px;
+ font-size: 13px;
+ }
+ }
+ }
}
// 표시변경
@@ -1687,10 +1731,14 @@ $alert-color: #101010;
}
.circuit-title-sel{
padding-bottom: 14px;
- .outline-form{
- span{
- color: #62C207;
- }
+ .circuit-title{
+ font-size: 12px;
+ color: #62C207;
+ margin-bottom: 5px;
+ }
+ .circuit-sel-wrap{
+ display: flex;
+ align-items: center;
.grid-select{
.sort-select{
border: 1px solid #4E9E04;
@@ -2180,3 +2228,53 @@ $alert-color: #101010;
justify-content: flex-end;
}
}
+
+.pop-spinner{
+ position: absolute;
+ bottom: 10px;
+ left: 5px;
+ width: calc(100% - 10px);
+ height: calc(100% - 49px);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: rgba($color: #101010, $alpha: 0.5);
+ z-index: 2000000;
+ .loader {
+ font-size: 10px;
+ width: 1.2em;
+ height: 1.2em;
+ border-radius: 50%;
+ position: relative;
+ text-indent: -9999em;
+ animation: mulShdSpin 1.1s infinite ease;
+ transform: translateZ(0);
+ }
+ @keyframes mulShdSpin {
+ 0%,
+ 100% {
+ box-shadow: 0em -2.6em 0em 0em #fff, 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), -1.8em 1.8em 0 0em rgba(0, 0, 0, 0.2), -2.6em 0em 0 0em rgba(255, 255, 255, 0.5), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7);
+ }
+ 12.5% {
+ box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.7), 1.8em -1.8em 0 0em #fff, 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5);
+ }
+ 25% {
+ box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.5), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7), 2.5em 0em 0 0em #fff, 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
+ }
+ 37.5% {
+ box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5), 2.5em 0em 0 0em rgba(255, 255, 255, 0.7), 1.75em 1.75em 0 0em #fff, 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
+ }
+ 50% {
+ box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), 2.5em 0em 0 0em rgba(255, 255, 255, 0.5), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.7), 0em 2.5em 0 0em #fff, -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
+ }
+ 62.5% {
+ box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.5), 0em 2.5em 0 0em rgba(255, 255, 255, 0.7), -1.8em 1.8em 0 0em #fff, -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
+ }
+ 75% {
+ box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), 0em 2.5em 0 0em rgba(255, 255, 255, 0.5), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.7), -2.6em 0em 0 0em #fff, -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
+ }
+ 87.5% {
+ box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.5), -2.6em 0em 0 0em rgba(255, 255, 255, 0.7), -1.8em -1.8em 0 0em #fff;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js
index 6ad06e45..935097b0 100644
--- a/src/util/canvas-util.js
+++ b/src/util/canvas-util.js
@@ -649,7 +649,7 @@ export function calculateDistance(point, line) {
* @param {Object} point2 - 두 번째 점 { x: number, y: number }
* @returns {number} 두 점 사이의 거리
*/
-function calculateDistancePoint(point1, point2) {
+export function calculateDistancePoint(point1, point2) {
return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2))
}
@@ -1035,3 +1035,22 @@ export function calculateVisibleModuleHeight(sourceWidth, sourceHeight, angle, d
height: Number(visibleHeight.toFixed(1)), // 소수점 두 자리로 고정
}
}
+
+//숫자, 몇자리수
+export function toFixedWithoutRounding(number, decimals) {
+ return Math.floor(number * Math.pow(10, decimals)) / Math.pow(10, decimals)
+}
+
+export function getTrianglePoints(triangle) {
+ const matrix = triangle.calcTransformMatrix()
+ const w = triangle.width / 2
+ const h = triangle.height / 2
+
+ const points = [
+ { x: 0, y: -h },
+ { x: -w, y: h },
+ { x: w, y: h },
+ ]
+
+ return points.map((point) => fabric.util.transformPoint(point, matrix))
+}
diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js
index 5b5c1bab..f6916e55 100644
--- a/src/util/qpolygon-utils.js
+++ b/src/util/qpolygon-utils.js
@@ -322,7 +322,7 @@ export const drawGabledRoof = (roofId, canvas, textMode) => {
const wallLines = canvas?.getObjects().find((object) => object.name === POLYGON_TYPE.WALL && object.attributes.roofId === roof.id).lines
const hasNonParallelLines = roofLines.filter((line) => line.x1 !== line.x2 && line.y1 !== line.y2)
if (hasNonParallelLines.length > 0) {
- alert('대각선이 존재합니다.')
+ // alert('대각선이 존재합니다.')
return
}
@@ -650,7 +650,7 @@ export const drawShedRoof = (roofId, canvas, textMode) => {
const roof = canvas?.getObjects().find((object) => object.id === roofId)
const hasNonParallelLines = roof.lines.filter((line) => Math.abs(line.x1 - line.x2) > 1 && Math.abs(line.y1 - line.y2) > 1)
if (hasNonParallelLines.length > 0) {
- alert('대각선이 존재합니다.')
+ // alert('대각선이 존재합니다.')
return
}
@@ -5861,3 +5861,18 @@ export const calcLineActualSize = (points, degree) => {
}
return Big(planeSize).pow(2).plus(height.pow(2)).sqrt().abs().round().toNumber()
}
+
+export const createLinesFromPolygon = (points) => {
+ const lines = []
+ for (let i = 0; i < points.length; i++) {
+ const nextIndex = (i + 1) % points.length
+ const line = new fabric.Line([points[i].x, points[i].y, points[nextIndex].x, points[nextIndex].y], {
+ stroke: 'red',
+ strokeWidth: 2,
+ selectable: false,
+ evented: false,
+ })
+ lines.push(line)
+ }
+ return lines
+}
diff --git a/tailwind.config.js b/tailwind.config.js
index efe48113..ae588bc1 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,5 +1,3 @@
-const { nextui } = require('@nextui-org/react')
-
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
@@ -12,11 +10,10 @@ module.exports = {
extend: {
backgroundImage: {
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
- 'gradient-conic':
- 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
+ 'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
},
},
},
darkMode: 'class',
- plugins: [nextui()],
+ plugins: [],
}