배치면 -> 오브젝트 배치 -> 개구,그림자 작업
This commit is contained in:
parent
d5f5aaa09f
commit
6c15375a53
@ -96,6 +96,10 @@ export const BATCH_TYPE = {
|
|||||||
OPENING_TEMP: 'openingTemp',
|
OPENING_TEMP: 'openingTemp',
|
||||||
SHADOW: 'shadow',
|
SHADOW: 'shadow',
|
||||||
SHADOW_TEMP: 'shadowTemp',
|
SHADOW_TEMP: 'shadowTemp',
|
||||||
|
TRIANGLE_DORMER: 'triangleDormer',
|
||||||
|
TRIANGLE_DORMER_TEMP: 'triangleDormerTemp',
|
||||||
|
PENTAGON_DORMER: 'pentagonDormer',
|
||||||
|
PENTAGON_DORMER_TEMP: 'pentagonDormerTemp',
|
||||||
}
|
}
|
||||||
// 오브젝트 배치 > 프리입력, 치수입력
|
// 오브젝트 배치 > 프리입력, 치수입력
|
||||||
export const INPUT_TYPE = {
|
export const INPUT_TYPE = {
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { useEffect, useState } from 'react'
|
|||||||
import { MENU } from '@/common/common'
|
import { MENU } from '@/common/common'
|
||||||
import { currentMenuState } from '@/store/canvasAtom'
|
import { currentMenuState } from '@/store/canvasAtom'
|
||||||
import { useSetRecoilState } from 'recoil'
|
import { useSetRecoilState } from 'recoil'
|
||||||
|
import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch'
|
||||||
export default function MenuDepth01(props) {
|
export default function MenuDepth01(props) {
|
||||||
const {
|
const {
|
||||||
setShowOutlineModal,
|
setShowOutlineModal,
|
||||||
@ -28,6 +28,9 @@ export default function MenuDepth01(props) {
|
|||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
const [activeMenu, setActiveMenu] = useState()
|
const [activeMenu, setActiveMenu] = useState()
|
||||||
const setCurrentMenu = useSetRecoilState(currentMenuState)
|
const setCurrentMenu = useSetRecoilState(currentMenuState)
|
||||||
|
|
||||||
|
const { deleteAllSurfacesAndObjects } = useSurfaceShapeBatch()
|
||||||
|
|
||||||
const onClickMenu = ({ id, menu, name }) => {
|
const onClickMenu = ({ id, menu, name }) => {
|
||||||
setActiveMenu(menu)
|
setActiveMenu(menu)
|
||||||
setShowOutlineModal(menu === MENU.ROOF_COVERING.EXTERIOR_WALL_LINE)
|
setShowOutlineModal(menu === MENU.ROOF_COVERING.EXTERIOR_WALL_LINE)
|
||||||
@ -60,6 +63,11 @@ export default function MenuDepth01(props) {
|
|||||||
setShowPlaceShapeDrawingModal(id === 1)
|
setShowPlaceShapeDrawingModal(id === 1)
|
||||||
setShowPlacementSurfaceSettingModal(id === 2)
|
setShowPlacementSurfaceSettingModal(id === 2)
|
||||||
setShowObjectSettingModal(id === 3)
|
setShowObjectSettingModal(id === 3)
|
||||||
|
|
||||||
|
//배치면 전체 삭제
|
||||||
|
if (id === 4) {
|
||||||
|
deleteAllSurfacesAndObjects()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'module') {
|
if (type === 'module') {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { useMessage } from '@/hooks/useMessage'
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
import WithDraggable from '@/components/common/draggable/withDraggable'
|
import WithDraggable from '@/components/common/draggable/WithDraggable'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import Orientation from '@/components/floor-plan/modal/basic/step/Orientation'
|
import Orientation from '@/components/floor-plan/modal/basic/step/Orientation'
|
||||||
import Module from '@/components/floor-plan/modal/basic/step/Module'
|
import Module from '@/components/floor-plan/modal/basic/step/Module'
|
||||||
|
|||||||
@ -3,12 +3,10 @@
|
|||||||
import { useState, useRef } from 'react'
|
import { useState, useRef } from 'react'
|
||||||
import { useRecoilValue } from 'recoil'
|
import { useRecoilValue } from 'recoil'
|
||||||
import { useMessage } from '@/hooks/useMessage'
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
import { INPUT_TYPE, BATCH_TYPE } from '@/common/common'
|
|
||||||
import { useEvent } from '@/hooks/useEvent'
|
import { useEvent } from '@/hooks/useEvent'
|
||||||
import { canvasState } from '@/store/canvasAtom'
|
import { canvasState } from '@/store/canvasAtom'
|
||||||
import { useSwal } from '@/hooks/useSwal'
|
import { useSwal } from '@/hooks/useSwal'
|
||||||
import { polygonToTurfPolygon, rectToPolygon, pointsToTurfPolygon } from '@/util/canvas-util'
|
import { useObjectBatch } from '@/hooks/object/useObjectBatch'
|
||||||
import * as turf from '@turf/turf'
|
|
||||||
|
|
||||||
import WithDraggable from '@/components/common/draggable/WithDraggable'
|
import WithDraggable from '@/components/common/draggable/WithDraggable'
|
||||||
import OpenSpace from '@/components/floor-plan/modal/object/type/OpenSpace'
|
import OpenSpace from '@/components/floor-plan/modal/object/type/OpenSpace'
|
||||||
@ -20,9 +18,8 @@ export default function ObjectSetting({ setShowObjectSettingModal }) {
|
|||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
const [buttonAct, setButtonAct] = useState(1)
|
const [buttonAct, setButtonAct] = useState(1)
|
||||||
const [preObjects, setPreObjects] = useState([])
|
|
||||||
const { addCanvasMouseEventListener, initEvent } = useEvent()
|
|
||||||
const { swalFire } = useSwal()
|
const { swalFire } = useSwal()
|
||||||
|
const { applyOpeningAndShadow } = useObjectBatch()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 개구배치, 그림자배치
|
* 개구배치, 그림자배치
|
||||||
@ -35,13 +32,8 @@ export default function ObjectSetting({ setShowObjectSettingModal }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const applyObject = () => {
|
const applyObject = () => {
|
||||||
setShowObjectSettingModal(false)
|
|
||||||
|
|
||||||
let preObjectsArray = preObjects
|
|
||||||
const surfaceShapePolygons = canvas?.getObjects().filter((obj) => obj.name === 'surfaceShapeBatch')
|
const surfaceShapePolygons = canvas?.getObjects().filter((obj) => obj.name === 'surfaceShapeBatch')
|
||||||
|
|
||||||
console.log(preObjectsArray)
|
|
||||||
|
|
||||||
if (surfaceShapePolygons.length === 0) {
|
if (surfaceShapePolygons.length === 0) {
|
||||||
swalFire({ text: '지붕이 없어요 지붕부터 그리세요', icon: 'error' })
|
swalFire({ text: '지붕이 없어요 지붕부터 그리세요', icon: 'error' })
|
||||||
return
|
return
|
||||||
@ -49,121 +41,7 @@ export default function ObjectSetting({ setShowObjectSettingModal }) {
|
|||||||
|
|
||||||
//개구배치, 그림자배치
|
//개구배치, 그림자배치
|
||||||
if (buttonAct === 1 || buttonAct === 2) {
|
if (buttonAct === 1 || buttonAct === 2) {
|
||||||
const type = objectPlacement.typeRef.current.find((radio) => radio.checked).value
|
applyOpeningAndShadow(objectPlacement, buttonAct, surfaceShapePolygons, setShowObjectSettingModal)
|
||||||
const isCrossChecked = objectPlacement.isCrossRef.current.checked
|
|
||||||
|
|
||||||
let rect, isDown, origX, origY
|
|
||||||
let selectedSurface
|
|
||||||
|
|
||||||
//프리입력
|
|
||||||
if (type === INPUT_TYPE.FREE) {
|
|
||||||
addCanvasMouseEventListener('mouse:down', (e) => {
|
|
||||||
isDown = true
|
|
||||||
const pointer = canvas.getPointer(e.e)
|
|
||||||
|
|
||||||
surfaceShapePolygons.forEach((surface) => {
|
|
||||||
if (surface.inPolygon({ x: pointer.x, y: pointer.y })) {
|
|
||||||
selectedSurface = surface
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!selectedSurface) {
|
|
||||||
swalFire({ text: '지붕안에 그려야해요', icon: 'error' })
|
|
||||||
setShowObjectSettingModal(true) //메뉴보이고
|
|
||||||
initEvent() //이벤트 초기화
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
origX = pointer.x
|
|
||||||
origY = pointer.y
|
|
||||||
|
|
||||||
rect = new fabric.Rect({
|
|
||||||
left: origX,
|
|
||||||
top: origY,
|
|
||||||
originX: 'left',
|
|
||||||
originY: 'top',
|
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
angle: 0,
|
|
||||||
stroke: 'black',
|
|
||||||
})
|
|
||||||
|
|
||||||
//개구냐 그림자냐에 따라 변경
|
|
||||||
rect.set({
|
|
||||||
fill: buttonAct === 1 ? 'white' : 'rgba(0, 0, 0, 0.3)',
|
|
||||||
name: buttonAct === 1 ? BATCH_TYPE.OPENING_TEMP : BATCH_TYPE.SHADOW_TEMP,
|
|
||||||
})
|
|
||||||
|
|
||||||
canvas?.add(rect)
|
|
||||||
})
|
|
||||||
|
|
||||||
addCanvasMouseEventListener('mouse:move', (e) => {
|
|
||||||
if (!isDown) return
|
|
||||||
|
|
||||||
if (selectedSurface) {
|
|
||||||
const pointer = canvas.getPointer(e.e)
|
|
||||||
const width = pointer.x - origX
|
|
||||||
const height = pointer.y - origY
|
|
||||||
|
|
||||||
rect.set({ width: Math.abs(width), height: Math.abs(height) })
|
|
||||||
|
|
||||||
if (width < 0) {
|
|
||||||
rect.set({ left: Math.abs(pointer.x) })
|
|
||||||
}
|
|
||||||
if (height < 0) {
|
|
||||||
rect.set({ top: Math.abs(pointer.y) })
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas?.renderAll()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
addCanvasMouseEventListener('mouse:up', (e) => {
|
|
||||||
if (rect) {
|
|
||||||
const rectPolygon = pointsToTurfPolygon(rectToPolygon(rect))
|
|
||||||
const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
|
|
||||||
|
|
||||||
//지붕 밖으로 그렸을때
|
|
||||||
if (!turf.booleanWithin(rectPolygon, selectedSurfacePolygon)) {
|
|
||||||
swalFire({ text: '지붕안에 그리라고요...', icon: 'error' })
|
|
||||||
//일단 지워
|
|
||||||
const deleteTarget = canvas?.getObjects().filter((obj) => obj.name === BATCH_TYPE.OPENING_TEMP || obj.name === BATCH_TYPE.SHADOW_TEMP)
|
|
||||||
canvas?.remove(...deleteTarget)
|
|
||||||
setShowObjectSettingModal(true) //메뉴보이고
|
|
||||||
initEvent() //이벤트 초기화
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (!isCrossChecked) {
|
|
||||||
// const isCross = preObjectsArray.some((object) => turf.booleanOverlap(pointsToTurfPolygon(rectToPolygon(object), rectPolygon)))
|
|
||||||
|
|
||||||
// console.log(isCross)
|
|
||||||
|
|
||||||
// if (isCross) {
|
|
||||||
// swalFire({ text: '겹치기 불가요...', icon: 'error' })
|
|
||||||
// const deleteTarget = canvas?.getObjects().filter((obj) => obj.name === BATCH_TYPE.OPENING_TEMP || obj.name === BATCH_TYPE.SHADOW_TEMP)
|
|
||||||
// canvas?.remove(...deleteTarget)
|
|
||||||
// setShowObjectSettingModal(true) //메뉴보이고
|
|
||||||
// initEvent() //이벤트 초기화
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
isDown = false
|
|
||||||
const complateName = buttonAct === 1 ? BATCH_TYPE.OPENING : BATCH_TYPE.SHADOW
|
|
||||||
rect.set({ name: complateName })
|
|
||||||
rect.setCoords()
|
|
||||||
|
|
||||||
preObjectsArray.push(rect)
|
|
||||||
|
|
||||||
console.log('preObjectsArray', preObjectsArray)
|
|
||||||
setPreObjects(preObjectsArray)
|
|
||||||
|
|
||||||
setShowObjectSettingModal(true) //메뉴보이고
|
|
||||||
initEvent()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,23 +1,45 @@
|
|||||||
import { forwardRef } from 'react'
|
import { forwardRef, useState, useEffect } from 'react'
|
||||||
import { useMessage } from '@/hooks/useMessage'
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
import { INPUT_TYPE } from '@/common/common'
|
import { INPUT_TYPE } from '@/common/common'
|
||||||
|
|
||||||
const OpenSpace = forwardRef((props, refs) => {
|
const OpenSpace = forwardRef((props, refs) => {
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
|
const [selectedType, setSelectedType] = useState(INPUT_TYPE.FREE)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedType === INPUT_TYPE.FREE) {
|
||||||
|
refs.widthRef.current.value = 0
|
||||||
|
refs.heightRef.current.value = 0
|
||||||
|
}
|
||||||
|
}, [selectedType])
|
||||||
|
|
||||||
//체크하면 값바꿈
|
//체크하면 값바꿈
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="discrimination-box mb10">
|
<div className="discrimination-box mb10">
|
||||||
<div className="mb-box">
|
<div className="mb-box">
|
||||||
<div className="d-check-radio pop">
|
<div className="d-check-radio pop">
|
||||||
<input type="radio" name="radio01" id="ra01" value={INPUT_TYPE.FREE} defaultChecked ref={(el) => (refs.typeRef.current[0] = el)} />
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="radio01"
|
||||||
|
id="ra01"
|
||||||
|
value={INPUT_TYPE.FREE}
|
||||||
|
defaultChecked
|
||||||
|
ref={(el) => (refs.typeRef.current[0] = el)}
|
||||||
|
onClick={() => setSelectedType(INPUT_TYPE.FREE)}
|
||||||
|
/>
|
||||||
<label htmlFor="ra01">{getMessage('modal.object.setting.free.input')}</label>
|
<label htmlFor="ra01">{getMessage('modal.object.setting.free.input')}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-box">
|
<div className="mb-box">
|
||||||
<div className="d-check-radio pop">
|
<div className="d-check-radio pop">
|
||||||
<input type="radio" name="radio01" id="ra02" value={INPUT_TYPE.DIMENSION} ref={(el) => (refs.typeRef.current[1] = el)} />
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="radio01"
|
||||||
|
id="ra02"
|
||||||
|
value={INPUT_TYPE.DIMENSION}
|
||||||
|
ref={(el) => (refs.typeRef.current[1] = el)}
|
||||||
|
onClick={() => setSelectedType(INPUT_TYPE.DIMENSION)}
|
||||||
|
/>
|
||||||
<label htmlFor="ra02">{getMessage('modal.object.setting.size.input')}</label>
|
<label htmlFor="ra02">{getMessage('modal.object.setting.size.input')}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -29,7 +51,13 @@ const OpenSpace = forwardRef((props, refs) => {
|
|||||||
<div className="eaves-keraba-td">
|
<div className="eaves-keraba-td">
|
||||||
<div className="outline-form">
|
<div className="outline-form">
|
||||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||||
<input type="text" className="input-origin block" placeholder={0} ref={refs.widthRef} />
|
<input
|
||||||
|
type="text"
|
||||||
|
className="input-origin block"
|
||||||
|
placeholder={0}
|
||||||
|
ref={refs.widthRef}
|
||||||
|
disabled={selectedType !== INPUT_TYPE.DIMENSION}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span className="thin">mm</span>
|
<span className="thin">mm</span>
|
||||||
</div>
|
</div>
|
||||||
@ -40,7 +68,13 @@ const OpenSpace = forwardRef((props, refs) => {
|
|||||||
<div className="eaves-keraba-td">
|
<div className="eaves-keraba-td">
|
||||||
<div className="outline-form">
|
<div className="outline-form">
|
||||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||||
<input type="text" className="input-origin block" placeholder={0} ref={refs.heightRef} />
|
<input
|
||||||
|
type="text"
|
||||||
|
className="input-origin block"
|
||||||
|
placeholder={0}
|
||||||
|
ref={refs.heightRef}
|
||||||
|
disabled={selectedType !== INPUT_TYPE.DIMENSION}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span className="thin">mm</span>
|
<span className="thin">mm</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,20 +1,45 @@
|
|||||||
import { forwardRef } from 'react'
|
import { forwardRef, useState, useEffect } from 'react'
|
||||||
import { useMessage } from '@/hooks/useMessage'
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
import { INPUT_TYPE } from '@/common/common'
|
import { INPUT_TYPE } from '@/common/common'
|
||||||
|
|
||||||
const Shadow = forwardRef((props, refs) => {
|
const Shadow = forwardRef((props, refs) => {
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
|
|
||||||
|
const [selectedType, setSelectedType] = useState(INPUT_TYPE.FREE)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedType === INPUT_TYPE.FREE) {
|
||||||
|
refs.widthRef.current.value = 0
|
||||||
|
refs.heightRef.current.value = 0
|
||||||
|
}
|
||||||
|
}, [selectedType])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="discrimination-box mb10">
|
<div className="discrimination-box mb10">
|
||||||
<div className="mb-box">
|
<div className="mb-box">
|
||||||
<div className="d-check-radio pop">
|
<div className="d-check-radio pop">
|
||||||
<input type="radio" name="radio01" id="ra01" value={INPUT_TYPE.FREE} defaultChecked ref={(el) => (refs.typeRef.current[0] = el)} />
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="radio01"
|
||||||
|
id="ra01"
|
||||||
|
value={INPUT_TYPE.FREE}
|
||||||
|
defaultChecked
|
||||||
|
ref={(el) => (refs.typeRef.current[0] = el)}
|
||||||
|
onClick={() => setSelectedType(INPUT_TYPE.FREE)}
|
||||||
|
/>
|
||||||
<label htmlFor="ra01">{getMessage('modal.object.setting.free.input')}</label>
|
<label htmlFor="ra01">{getMessage('modal.object.setting.free.input')}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-box">
|
<div className="mb-box">
|
||||||
<div className="d-check-radio pop">
|
<div className="d-check-radio pop">
|
||||||
<input type="radio" name="radio01" id="ra02" value={INPUT_TYPE.DIMENSION} ref={(el) => (refs.typeRef.current[1] = el)} />
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="radio01"
|
||||||
|
id="ra02"
|
||||||
|
value={INPUT_TYPE.DIMENSION}
|
||||||
|
ref={(el) => (refs.typeRef.current[1] = el)}
|
||||||
|
onClick={() => setSelectedType(INPUT_TYPE.DIMENSION)}
|
||||||
|
/>
|
||||||
<label htmlFor="ra02">{getMessage('modal.object.setting.size.input')}</label>
|
<label htmlFor="ra02">{getMessage('modal.object.setting.size.input')}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -26,7 +51,13 @@ const Shadow = forwardRef((props, refs) => {
|
|||||||
<div className="eaves-keraba-td">
|
<div className="eaves-keraba-td">
|
||||||
<div className="outline-form">
|
<div className="outline-form">
|
||||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||||
<input type="text" className="input-origin block" placeholder={0} ref={refs.widthRef} />
|
<input
|
||||||
|
type="text"
|
||||||
|
className="input-origin block"
|
||||||
|
placeholder={0}
|
||||||
|
ref={refs.widthRef}
|
||||||
|
disabled={selectedType !== INPUT_TYPE.DIMENSION}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span className="thin">mm</span>
|
<span className="thin">mm</span>
|
||||||
</div>
|
</div>
|
||||||
@ -37,7 +68,13 @@ const Shadow = forwardRef((props, refs) => {
|
|||||||
<div className="eaves-keraba-td">
|
<div className="eaves-keraba-td">
|
||||||
<div className="outline-form">
|
<div className="outline-form">
|
||||||
<div className="input-grid mr5" style={{ width: '100px' }}>
|
<div className="input-grid mr5" style={{ width: '100px' }}>
|
||||||
<input type="text" className="input-origin block" placeholder={0} ref={refs.heightRef} />
|
<input
|
||||||
|
type="text"
|
||||||
|
className="input-origin block"
|
||||||
|
placeholder={0}
|
||||||
|
ref={refs.heightRef}
|
||||||
|
disabled={selectedType !== INPUT_TYPE.DIMENSION}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span className="thin">mm</span>
|
<span className="thin">mm</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,6 +1,210 @@
|
|||||||
|
'use client'
|
||||||
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
|
import { canvasState } from '@/store/canvasAtom'
|
||||||
|
import { INPUT_TYPE, BATCH_TYPE } from '@/common/common'
|
||||||
|
import { useEvent } from '@/hooks/useEvent'
|
||||||
|
import { polygonToTurfPolygon, rectToPolygon, pointsToTurfPolygon } from '@/util/canvas-util'
|
||||||
|
import { useSwal } from '@/hooks/useSwal'
|
||||||
|
import * as turf from '@turf/turf'
|
||||||
|
|
||||||
export function useObjectBatch() {
|
export function useObjectBatch() {
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
|
const { addCanvasMouseEventListener, initEvent } = useEvent()
|
||||||
|
const { swalFire } = useSwal()
|
||||||
|
|
||||||
const openObjectBatch = () => {}
|
const applyOpeningAndShadow = (objectPlacement, buttonAct, surfaceShapePolygons, setShowObjectSettingModal) => {
|
||||||
|
const selectedType = objectPlacement.typeRef.current.find((radio) => radio.checked).value
|
||||||
|
const isCrossChecked = buttonAct === 1 ? objectPlacement.isCrossRef.current.checked : false
|
||||||
|
const objTempName = buttonAct === 1 ? BATCH_TYPE.OPENING_TEMP : BATCH_TYPE.SHADOW_TEMP
|
||||||
|
const objName = buttonAct === 1 ? BATCH_TYPE.OPENING : BATCH_TYPE.SHADOW
|
||||||
|
|
||||||
|
let rect, isDown, origX, origY
|
||||||
|
let selectedSurface
|
||||||
|
|
||||||
|
//프리입력
|
||||||
|
if (selectedType === INPUT_TYPE.FREE) {
|
||||||
|
addCanvasMouseEventListener('mouse:down', (e) => {
|
||||||
|
isDown = true
|
||||||
|
const pointer = canvas.getPointer(e.e)
|
||||||
|
|
||||||
|
surfaceShapePolygons.forEach((surface) => {
|
||||||
|
if (surface.inPolygon({ x: pointer.x, y: pointer.y })) {
|
||||||
|
selectedSurface = surface
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!selectedSurface) {
|
||||||
|
swalFire({ text: '지붕안에 그려야해요', icon: 'error' })
|
||||||
|
initEvent() //이벤트 초기화
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
origX = pointer.x
|
||||||
|
origY = pointer.y
|
||||||
|
|
||||||
|
rect = new fabric.Rect({
|
||||||
|
left: origX,
|
||||||
|
top: origY,
|
||||||
|
originX: 'left',
|
||||||
|
originY: 'top',
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
angle: 0,
|
||||||
|
stroke: 'black',
|
||||||
|
})
|
||||||
|
|
||||||
|
//개구냐 그림자냐에 따라 변경
|
||||||
|
rect.set({
|
||||||
|
fill: buttonAct === 1 ? 'white' : 'rgba(0, 0, 0, 0.4)',
|
||||||
|
name: objTempName,
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas?.add(rect)
|
||||||
|
})
|
||||||
|
|
||||||
|
addCanvasMouseEventListener('mouse:move', (e) => {
|
||||||
|
if (!isDown) return
|
||||||
|
|
||||||
|
if (selectedSurface) {
|
||||||
|
const pointer = canvas.getPointer(e.e)
|
||||||
|
const width = pointer.x - origX
|
||||||
|
const height = pointer.y - origY
|
||||||
|
|
||||||
|
rect.set({ width: Math.abs(width), height: Math.abs(height) })
|
||||||
|
|
||||||
|
if (width < 0) {
|
||||||
|
rect.set({ left: Math.abs(pointer.x) })
|
||||||
|
}
|
||||||
|
if (height < 0) {
|
||||||
|
rect.set({ top: Math.abs(pointer.y) })
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas?.renderAll()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
addCanvasMouseEventListener('mouse:up', (e) => {
|
||||||
|
if (rect) {
|
||||||
|
const rectPolygon = pointsToTurfPolygon(rectToPolygon(rect))
|
||||||
|
const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
|
||||||
|
|
||||||
|
//지붕 밖으로 그렸을때
|
||||||
|
if (!turf.booleanWithin(rectPolygon, selectedSurfacePolygon)) {
|
||||||
|
swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' })
|
||||||
|
//일단 지워
|
||||||
|
deleteTempObjects(setShowObjectSettingModal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCrossChecked) {
|
||||||
|
const preObjects = canvas?.getObjects().filter((obj) => obj.name === BATCH_TYPE.OPENING || obj.name === BATCH_TYPE.SHADOW)
|
||||||
|
const preObjectsArray = preObjects.map((obj) => rectToPolygon(obj))
|
||||||
|
const isCross = preObjectsArray.some((object) => turf.booleanOverlap(pointsToTurfPolygon(object), rectPolygon))
|
||||||
|
|
||||||
|
if (isCross) {
|
||||||
|
swalFire({ text: '겹치기 불가요...', icon: 'error' })
|
||||||
|
deleteTempObjects(setShowObjectSettingModal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isDown = false
|
||||||
|
rect.set({ name: objName })
|
||||||
|
rect.setCoords()
|
||||||
|
initEvent()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (selectedType === INPUT_TYPE.DIMENSION) {
|
||||||
|
const width = objectPlacement.widthRef.current.value / 10
|
||||||
|
const height = objectPlacement.heightRef.current.value / 10
|
||||||
|
|
||||||
|
if (width === '' || height === '' || width <= 0 || height <= 0) {
|
||||||
|
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// setShowObjectSettingModal(false) //메뉴보이고
|
||||||
|
addCanvasMouseEventListener('mouse:move', (e) => {
|
||||||
|
isDown = true
|
||||||
|
if (!isDown) return
|
||||||
|
|
||||||
|
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === objTempName)) //움직일때 일단 지워가면서 움직임
|
||||||
|
const pointer = canvas.getPointer(e.e)
|
||||||
|
|
||||||
|
surfaceShapePolygons.forEach((surface) => {
|
||||||
|
if (surface.inPolygon({ x: pointer.x, y: pointer.y })) {
|
||||||
|
selectedSurface = surface
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
rect = new fabric.Rect({
|
||||||
|
fill: 'white',
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 1,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
left: pointer.x - width / 2,
|
||||||
|
top: pointer.y - height / 2,
|
||||||
|
selectable: true,
|
||||||
|
lockMovementX: true,
|
||||||
|
lockMovementY: true,
|
||||||
|
lockRotation: true,
|
||||||
|
lockScalingX: true,
|
||||||
|
lockScalingY: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
//개구냐 그림자냐에 따라 변경
|
||||||
|
rect.set({
|
||||||
|
fill: buttonAct === 1 ? 'white' : 'rgba(0, 0, 0, 0.4)',
|
||||||
|
name: objTempName,
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas?.add(rect)
|
||||||
|
})
|
||||||
|
|
||||||
|
addCanvasMouseEventListener('mouse:up', (e) => {
|
||||||
|
if (rect) {
|
||||||
|
const rectPolygon = pointsToTurfPolygon(rectToPolygon(rect))
|
||||||
|
const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
|
||||||
|
|
||||||
|
//지붕 밖으로 그렸을때
|
||||||
|
if (!turf.booleanWithin(rectPolygon, selectedSurfacePolygon)) {
|
||||||
|
swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' })
|
||||||
|
//일단 지워
|
||||||
|
deleteTempObjects(setShowObjectSettingModal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCrossChecked) {
|
||||||
|
const preObjects = canvas?.getObjects().filter((obj) => obj.name === BATCH_TYPE.OPENING || obj.name === BATCH_TYPE.SHADOW)
|
||||||
|
const preObjectsArray = preObjects.map((obj) => rectToPolygon(obj))
|
||||||
|
const isCross = preObjectsArray.some((object) => turf.booleanOverlap(pointsToTurfPolygon(object), rectPolygon))
|
||||||
|
|
||||||
|
if (isCross) {
|
||||||
|
swalFire({ text: '겹치기 불가요...', icon: 'error' })
|
||||||
|
deleteTempObjects(setShowObjectSettingModal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isDown = false
|
||||||
|
rect.set({ name: objName })
|
||||||
|
rect.setCoords()
|
||||||
|
initEvent()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteTempObjects = (setShowObjectSettingModal) => {
|
||||||
|
const deleteTarget = canvas?.getObjects().filter((obj) => obj.name === BATCH_TYPE.OPENING_TEMP || obj.name === BATCH_TYPE.SHADOW_TEMP)
|
||||||
|
canvas?.remove(...deleteTarget)
|
||||||
|
initEvent() //이벤트 초기화
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
applyOpeningAndShadow,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useRecoilValue } from 'recoil'
|
import { useRecoilValue } from 'recoil'
|
||||||
import { canvasState } from '@/store/canvasAtom'
|
import { canvasState } from '@/store/canvasAtom'
|
||||||
import { MENU } from '@/common/common'
|
import { MENU, BATCH_TYPE } from '@/common/common'
|
||||||
import { getIntersectionPoint, setSurfaceShapePattern } from '@/util/canvas-util'
|
import { getIntersectionPoint, setSurfaceShapePattern } from '@/util/canvas-util'
|
||||||
import { degreesToRadians } from '@turf/turf'
|
import { degreesToRadians } from '@turf/turf'
|
||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
@ -131,23 +131,23 @@ export function useSurfaceShapeBatch() {
|
|||||||
|
|
||||||
if (surfaceId === 1) {
|
if (surfaceId === 1) {
|
||||||
if (length1 === 0) {
|
if (length1 === 0) {
|
||||||
swalFire({ text: getMessage('surface.shape.validate.size'), icon: 'error' })
|
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
|
||||||
check = false
|
check = false
|
||||||
}
|
}
|
||||||
if (length2 === 0) {
|
if (length2 === 0) {
|
||||||
if (length3 === 0) {
|
if (length3 === 0) {
|
||||||
swalFire({ text: getMessage('surface.shape.validate.size'), icon: 'error' })
|
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
|
||||||
check = false
|
check = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ([2, 4].includes(surfaceId)) {
|
} else if ([2, 4].includes(surfaceId)) {
|
||||||
if (length1 === 0 || length2 === 0) {
|
if (length1 === 0 || length2 === 0) {
|
||||||
swalFire({ text: getMessage('surface.shape.validate.size'), icon: 'error' })
|
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
|
||||||
check = false
|
check = false
|
||||||
}
|
}
|
||||||
} else if ([3, 5, 6, 15, 18].includes(surfaceId)) {
|
} else if ([3, 5, 6, 15, 18].includes(surfaceId)) {
|
||||||
if (length1 === 0 || length2 === 0 || length3 === 0) {
|
if (length1 === 0 || length2 === 0 || length3 === 0) {
|
||||||
swalFire({ text: getMessage('surface.shape.validate.size'), icon: 'error' })
|
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
|
||||||
check = false
|
check = false
|
||||||
}
|
}
|
||||||
if (surfaceId === 3 && length3 > length1) {
|
if (surfaceId === 3 && length3 > length1) {
|
||||||
@ -173,7 +173,7 @@ export function useSurfaceShapeBatch() {
|
|||||||
}
|
}
|
||||||
} else if ([8, 12, 13, 16, 17].includes(surfaceId)) {
|
} else if ([8, 12, 13, 16, 17].includes(surfaceId)) {
|
||||||
if (length1 === 0 || length2 === 0 || length3 === 0 || length4 === 0) {
|
if (length1 === 0 || length2 === 0 || length3 === 0 || length4 === 0) {
|
||||||
swalFire({ text: getMessage('surface.shape.validate.size'), icon: 'error' })
|
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
|
||||||
check = false
|
check = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +201,7 @@ export function useSurfaceShapeBatch() {
|
|||||||
}
|
}
|
||||||
} else if ([7, 9, 10, 11, 14].includes(surfaceId)) {
|
} else if ([7, 9, 10, 11, 14].includes(surfaceId)) {
|
||||||
if (length1 === 0 || length2 === 0 || length3 === 0 || length4 === 0 || length5 === 0) {
|
if (length1 === 0 || length2 === 0 || length3 === 0 || length4 === 0 || length5 === 0) {
|
||||||
swalFire({ text: getMessage('surface.shape.validate.size'), icon: 'error' })
|
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
|
||||||
check = false
|
check = false
|
||||||
}
|
}
|
||||||
if (surfaceId === 9 || surfaceId === 10 || surfaceId === 11) {
|
if (surfaceId === 9 || surfaceId === 10 || surfaceId === 11) {
|
||||||
@ -564,7 +564,27 @@ export function useSurfaceShapeBatch() {
|
|||||||
|
|
||||||
return points
|
return points
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deleteAllSurfacesAndObjects = () => {
|
||||||
|
swalFire({
|
||||||
|
text: '삭제 ㄱㄱ?',
|
||||||
|
type: 'confirm',
|
||||||
|
confirmFn: () => {
|
||||||
|
canvas?.getObjects().forEach((obj) => {
|
||||||
|
if (obj.name === MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH || obj.name === BATCH_TYPE.OPENING || obj.name === BATCH_TYPE.SHADOW) {
|
||||||
|
canvas?.remove(obj)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
swalFire({ text: '삭제 완료 되었습니다.' })
|
||||||
|
},
|
||||||
|
denyFn: () => {
|
||||||
|
swalFire({ text: '취소되었습니다.' })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
applySurfaceShape,
|
applySurfaceShape,
|
||||||
|
deleteAllSurfacesAndObjects,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -470,7 +470,7 @@
|
|||||||
"main.popup.login.validate1": "入力したパスワードが異なります。",
|
"main.popup.login.validate1": "入力したパスワードが異なります。",
|
||||||
"main.popup.login.validate2": "半角10文字以内で入力してください。",
|
"main.popup.login.validate2": "半角10文字以内で入力してください。",
|
||||||
"main.popup.login.success": "パスワードが変更されました。",
|
"main.popup.login.success": "パスワードが変更されました。",
|
||||||
"surface.shape.validate.size": "寸法を入力してください.",
|
"common.canvas.validate.size": "寸法を入力してください.",
|
||||||
"surface.shape.validate.size.1to2": "①길이는 ②보다 큰 값을 넣어주세요.",
|
"surface.shape.validate.size.1to2": "①길이는 ②보다 큰 값을 넣어주세요.",
|
||||||
"surface.shape.validate.size.1to3": "①길이는 ③보다 큰 값을 넣어주세요.",
|
"surface.shape.validate.size.1to3": "①길이는 ③보다 큰 값을 넣어주세요.",
|
||||||
"surface.shape.validate.size.1to23": "①길이는 ②+③보다 큰 값을 넣어주세요.",
|
"surface.shape.validate.size.1to23": "①길이는 ②+③보다 큰 값을 넣어주세요.",
|
||||||
|
|||||||
@ -474,7 +474,7 @@
|
|||||||
"main.popup.login.validate1": "입력한 패스워드가 다릅니다.",
|
"main.popup.login.validate1": "입력한 패스워드가 다릅니다.",
|
||||||
"main.popup.login.validate2": "반각 10자 이내로 입력해주세요.",
|
"main.popup.login.validate2": "반각 10자 이내로 입력해주세요.",
|
||||||
"main.popup.login.success": "비밀번호가 변경되었습니다.",
|
"main.popup.login.success": "비밀번호가 변경되었습니다.",
|
||||||
"surface.shape.validate.size": "사이즈를 입력해 주세요.",
|
"common.canvas.validate.size": "사이즈를 입력해 주세요.",
|
||||||
"surface.shape.validate.size.1to2": "①길이는 ②보다 큰 값을 넣어주세요.",
|
"surface.shape.validate.size.1to2": "①길이는 ②보다 큰 값을 넣어주세요.",
|
||||||
"surface.shape.validate.size.1to3": "①길이는 ③보다 큰 값을 넣어주세요.",
|
"surface.shape.validate.size.1to3": "①길이는 ③보다 큰 값을 넣어주세요.",
|
||||||
"surface.shape.validate.size.1to23": "①길이는 ②+③보다 큰 값을 넣어주세요.",
|
"surface.shape.validate.size.1to23": "①길이는 ②+③보다 큰 값을 넣어주세요.",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user