면형상추가
This commit is contained in:
parent
c257ecc118
commit
e9c4be5939
@ -75,7 +75,7 @@ export default async function RootLayout({ children }) {
|
|||||||
<QcastProvider>{children}</QcastProvider>
|
<QcastProvider>{children}</QcastProvider>
|
||||||
)}
|
)}
|
||||||
<ToastContainer />
|
<ToastContainer />
|
||||||
{/* <QModal /> */}
|
<QModal />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
</RecoilRootWrapper>
|
</RecoilRootWrapper>
|
||||||
|
|||||||
@ -93,7 +93,9 @@ export const LineType = {
|
|||||||
// 오브젝트 배치 > 개구배치, 그림자배치
|
// 오브젝트 배치 > 개구배치, 그림자배치
|
||||||
export const BATCH_TYPE = {
|
export const BATCH_TYPE = {
|
||||||
OPENING: 'opening',
|
OPENING: 'opening',
|
||||||
|
OPENING_TEMP: 'openingTemp',
|
||||||
SHADOW: 'shadow',
|
SHADOW: 'shadow',
|
||||||
|
SHADOW_TEMP: 'shadowTemp',
|
||||||
}
|
}
|
||||||
// 오브젝트 배치 > 프리입력, 치수입력
|
// 오브젝트 배치 > 프리입력, 치수입력
|
||||||
export const INPUT_TYPE = {
|
export const INPUT_TYPE = {
|
||||||
|
|||||||
@ -1,6 +1,16 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useState, useRef } from 'react'
|
||||||
|
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 { canvasState } from '@/store/canvasAtom'
|
||||||
|
import { useSwal } from '@/hooks/useSwal'
|
||||||
|
import { polygonToTurfPolygon, rectToPolygon, pointsToTurfPolygon } from '@/util/canvas-util'
|
||||||
|
import * as turf from '@turf/turf'
|
||||||
|
|
||||||
import WithDraggable from '@/components/common/draggable/WithDraggable'
|
import WithDraggable from '@/components/common/draggable/WithDraggable'
|
||||||
import { useState } from 'react'
|
|
||||||
import OpenSpace from '@/components/floor-plan/modal/object/type/OpenSpace'
|
import OpenSpace from '@/components/floor-plan/modal/object/type/OpenSpace'
|
||||||
import Shadow from '@/components/floor-plan/modal/object/type/Shadow'
|
import Shadow from '@/components/floor-plan/modal/object/type/Shadow'
|
||||||
import TriangleDormer from '@/components/floor-plan/modal/object/type/TriangleDormer'
|
import TriangleDormer from '@/components/floor-plan/modal/object/type/TriangleDormer'
|
||||||
@ -8,7 +18,155 @@ import PentagonDormer from '@/components/floor-plan/modal/object/type/PentagonDo
|
|||||||
|
|
||||||
export default function ObjectSetting({ setShowObjectSettingModal }) {
|
export default function ObjectSetting({ setShowObjectSettingModal }) {
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
|
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 objectPlacement = {
|
||||||
|
typeRef: useRef([]), //프리입력, 치수입력
|
||||||
|
widthRef: useRef(null),
|
||||||
|
heightRef: useRef(null),
|
||||||
|
isCrossRef: useRef(null),
|
||||||
|
}
|
||||||
|
|
||||||
|
const applyObject = () => {
|
||||||
|
setShowObjectSettingModal(false)
|
||||||
|
|
||||||
|
let preObjectsArray = preObjects
|
||||||
|
const surfaceShapePolygons = canvas?.getObjects().filter((obj) => obj.name === 'surfaceShapeBatch')
|
||||||
|
|
||||||
|
console.log(preObjectsArray)
|
||||||
|
|
||||||
|
if (surfaceShapePolygons.length === 0) {
|
||||||
|
swalFire({ text: '지붕이 없어요 지붕부터 그리세요', icon: 'error' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//개구배치, 그림자배치
|
||||||
|
if (buttonAct === 1 || buttonAct === 2) {
|
||||||
|
const type = objectPlacement.typeRef.current.find((radio) => radio.checked).value
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const buttonMenu = [
|
const buttonMenu = [
|
||||||
{ id: 1, name: getMessage('modal.object.setting.type.open.space.placement') },
|
{ id: 1, name: getMessage('modal.object.setting.type.open.space.placement') },
|
||||||
{ id: 2, name: getMessage('modal.object.setting.type.shadow.placement') },
|
{ id: 2, name: getMessage('modal.object.setting.type.shadow.placement') },
|
||||||
@ -34,13 +192,20 @@ export default function ObjectSetting({ setShowObjectSettingModal }) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="properties-setting-wrap outer">
|
<div className="properties-setting-wrap outer">
|
||||||
<div className="setting-tit">{getMessage('setting')}</div>
|
<div className="setting-tit">{getMessage('setting')}</div>
|
||||||
{buttonAct === 1 && <OpenSpace />}
|
{buttonAct === 1 && <OpenSpace ref={objectPlacement} />}
|
||||||
{buttonAct === 2 && <Shadow />}
|
{buttonAct === 2 && <Shadow ref={objectPlacement} />}
|
||||||
{buttonAct === 3 && <TriangleDormer />}
|
{buttonAct === 3 && <TriangleDormer />}
|
||||||
{buttonAct === 4 && <PentagonDormer />}
|
{buttonAct === 4 && <PentagonDormer />}
|
||||||
</div>
|
</div>
|
||||||
<div className="grid-btn-wrap">
|
<div className="grid-btn-wrap">
|
||||||
<button className="btn-frame modal act">{getMessage('write')}</button>
|
<button
|
||||||
|
className="btn-frame modal act"
|
||||||
|
onClick={() => {
|
||||||
|
applyObject()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{getMessage('write')}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,18 +1,23 @@
|
|||||||
|
import { forwardRef } from 'react'
|
||||||
import { useMessage } from '@/hooks/useMessage'
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
|
import { INPUT_TYPE } from '@/common/common'
|
||||||
|
|
||||||
export default function OpenSpace() {
|
const OpenSpace = forwardRef((props, refs) => {
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
|
|
||||||
|
//체크하면 값바꿈
|
||||||
|
|
||||||
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" />
|
<input type="radio" name="radio01" id="ra01" value={INPUT_TYPE.FREE} defaultChecked ref={(el) => (refs.typeRef.current[0] = el)} />
|
||||||
<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" />
|
<input type="radio" name="radio01" id="ra02" value={INPUT_TYPE.DIMENSION} ref={(el) => (refs.typeRef.current[1] = el)} />
|
||||||
<label htmlFor="ra02">{getMessage('modal.object.setting.size.input')}</label>
|
<label htmlFor="ra02">{getMessage('modal.object.setting.size.input')}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -24,7 +29,7 @@ export default function OpenSpace() {
|
|||||||
<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" defaultValue={100} />
|
<input type="text" className="input-origin block" placeholder={0} ref={refs.widthRef} />
|
||||||
</div>
|
</div>
|
||||||
<span className="thin">mm</span>
|
<span className="thin">mm</span>
|
||||||
</div>
|
</div>
|
||||||
@ -35,7 +40,7 @@ export default function OpenSpace() {
|
|||||||
<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" defaultValue={100} />
|
<input type="text" className="input-origin block" placeholder={0} ref={refs.heightRef} />
|
||||||
</div>
|
</div>
|
||||||
<span className="thin">mm</span>
|
<span className="thin">mm</span>
|
||||||
</div>
|
</div>
|
||||||
@ -45,9 +50,11 @@ export default function OpenSpace() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="d-check-box pop">
|
<div className="d-check-box pop">
|
||||||
<input type="checkbox" id="ch99" />
|
<input type="checkbox" id="ch99" ref={refs.isCrossRef} />
|
||||||
<label htmlFor="ch99">{getMessage('modal.object.setting.area.cross')}</label>
|
<label htmlFor="ch99">{getMessage('modal.object.setting.area.cross')}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
|
export default OpenSpace
|
||||||
|
|||||||
@ -1,18 +1,20 @@
|
|||||||
|
import { forwardRef } from 'react'
|
||||||
import { useMessage } from '@/hooks/useMessage'
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
|
import { INPUT_TYPE } from '@/common/common'
|
||||||
|
|
||||||
export default function Shadow() {
|
const Shadow = forwardRef((props, refs) => {
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
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" />
|
<input type="radio" name="radio01" id="ra01" value={INPUT_TYPE.FREE} defaultChecked ref={(el) => (refs.typeRef.current[0] = el)} />
|
||||||
<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" />
|
<input type="radio" name="radio01" id="ra02" value={INPUT_TYPE.DIMENSION} ref={(el) => (refs.typeRef.current[1] = el)} />
|
||||||
<label htmlFor="ra02">{getMessage('modal.object.setting.size.input')}</label>
|
<label htmlFor="ra02">{getMessage('modal.object.setting.size.input')}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -24,7 +26,7 @@ export default function Shadow() {
|
|||||||
<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" defaultValue={100} />
|
<input type="text" className="input-origin block" placeholder={0} ref={refs.widthRef} />
|
||||||
</div>
|
</div>
|
||||||
<span className="thin">mm</span>
|
<span className="thin">mm</span>
|
||||||
</div>
|
</div>
|
||||||
@ -35,7 +37,7 @@ export default function Shadow() {
|
|||||||
<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" defaultValue={100} />
|
<input type="text" className="input-origin block" placeholder={0} ref={refs.heightRef} />
|
||||||
</div>
|
</div>
|
||||||
<span className="thin">mm</span>
|
<span className="thin">mm</span>
|
||||||
</div>
|
</div>
|
||||||
@ -46,4 +48,6 @@ export default function Shadow() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
|
export default Shadow
|
||||||
|
|||||||
6
src/hooks/object/useObjectBatch.js
Normal file
6
src/hooks/object/useObjectBatch.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export function useObjectBatch() {
|
||||||
|
const { getMessage } = useMessage()
|
||||||
|
const canvas = useRecoilValue(canvasState)
|
||||||
|
|
||||||
|
const openObjectBatch = () => {}
|
||||||
|
}
|
||||||
@ -1,21 +1,22 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useRecoilValue } from 'recoil'
|
||||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
|
|
||||||
import { canvasState } from '@/store/canvasAtom'
|
import { canvasState } from '@/store/canvasAtom'
|
||||||
import { MENU } from '@/common/common'
|
import { MENU } from '@/common/common'
|
||||||
import { getIntersectionPoint } 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'
|
||||||
import { fabric } from 'fabric'
|
import { fabric } from 'fabric'
|
||||||
import { useSwal } from '@/hooks/useSwal'
|
import { useSwal } from '@/hooks/useSwal'
|
||||||
import { useMessage } from '@/hooks/useMessage'
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
|
import { useEvent } from '@/hooks/useEvent'
|
||||||
|
|
||||||
export function useSurfaceShapeBatch() {
|
export function useSurfaceShapeBatch() {
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
|
|
||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
const { swalFire } = useSwal()
|
const { swalFire } = useSwal()
|
||||||
|
const { addCanvasMouseEventListener, initEvent } = useEvent()
|
||||||
|
|
||||||
const applySurfaceShape = (surfaceRefs, selectedType, setShowPlacementSurfaceSettingModal) => {
|
const applySurfaceShape = (surfaceRefs, selectedType, setShowPlacementSurfaceSettingModal) => {
|
||||||
let length1, length2, length3, length4, length5
|
let length1, length2, length3, length4, length5
|
||||||
@ -57,7 +58,7 @@ export function useSurfaceShapeBatch() {
|
|||||||
let points = []
|
let points = []
|
||||||
if (checkSurfaceShape(surfaceId, { length1, length2, length3, length4, length5 })) {
|
if (checkSurfaceShape(surfaceId, { length1, length2, length3, length4, length5 })) {
|
||||||
setShowPlacementSurfaceSettingModal(false)
|
setShowPlacementSurfaceSettingModal(false)
|
||||||
canvas?.on('mouse:move', (e) => {
|
addCanvasMouseEventListener('mouse:move', (e) => {
|
||||||
if (!isDrawing) {
|
if (!isDrawing) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -110,15 +111,13 @@ export function useSurfaceShapeBatch() {
|
|||||||
obj.set({ direction: direction })
|
obj.set({ direction: direction })
|
||||||
obj.set({ originAngle: originAngle })
|
obj.set({ originAngle: originAngle })
|
||||||
|
|
||||||
// setCurrentPattern(obj)
|
|
||||||
canvas?.renderAll()
|
canvas?.renderAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
canvas?.on('mouse:down', (e) => {
|
addCanvasMouseEventListener('mouse:down', (e) => {
|
||||||
isDrawing = false
|
isDrawing = false
|
||||||
obj.set('name', MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH)
|
obj.set('name', MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH)
|
||||||
canvas?.off('mouse:down')
|
initEvent()
|
||||||
canvas.off('mouse:move')
|
|
||||||
setSurfaceShapePattern(obj)
|
setSurfaceShapePattern(obj)
|
||||||
setShowPlacementSurfaceSettingModal(true)
|
setShowPlacementSurfaceSettingModal(true)
|
||||||
})
|
})
|
||||||
@ -565,66 +564,6 @@ export function useSurfaceShapeBatch() {
|
|||||||
|
|
||||||
return points
|
return points
|
||||||
}
|
}
|
||||||
|
|
||||||
//면형상 선택 클릭시 지붕 패턴 입히기
|
|
||||||
const setSurfaceShapePattern = (polygon) => {
|
|
||||||
const ratio = window.devicePixelRatio || 1
|
|
||||||
|
|
||||||
let width = 265 / 10
|
|
||||||
let height = 150 / 10
|
|
||||||
let roofStyle = 2
|
|
||||||
const inputPatternSize = { width: width, height: height } //임시 사이즈
|
|
||||||
const patternSize = { ...inputPatternSize } // 입력된 값을 뒤집기 위해
|
|
||||||
|
|
||||||
if (polygon.direction === 'east' || polygon.direction === 'west') {
|
|
||||||
//세로형이면 width height를 바꿈
|
|
||||||
;[patternSize.width, patternSize.height] = [inputPatternSize.height, patternSize.width]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 패턴 소스를 위한 임시 캔버스 생성
|
|
||||||
const patternSourceCanvas = document.createElement('canvas')
|
|
||||||
patternSourceCanvas.width = polygon.width * ratio
|
|
||||||
patternSourceCanvas.height = polygon.height * ratio
|
|
||||||
const ctx = patternSourceCanvas.getContext('2d')
|
|
||||||
const offset = roofStyle === 1 ? 0 : patternSize.width / 2
|
|
||||||
|
|
||||||
const rows = Math.floor(patternSourceCanvas.height / patternSize.height)
|
|
||||||
const cols = Math.floor(patternSourceCanvas.width / patternSize.width)
|
|
||||||
|
|
||||||
ctx.strokeStyle = 'green'
|
|
||||||
ctx.lineWidth = 0.4
|
|
||||||
|
|
||||||
for (let row = 0; row <= rows; row++) {
|
|
||||||
const y = row * patternSize.height
|
|
||||||
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.moveTo(0, y) // 선 시작점
|
|
||||||
ctx.lineTo(patternSourceCanvas.width, y) // 선 끝점
|
|
||||||
ctx.stroke()
|
|
||||||
|
|
||||||
for (let col = 0; col <= cols; col++) {
|
|
||||||
const x = col * patternSize.width + (row % 2 === 0 ? 0 : offset)
|
|
||||||
const yStart = row * patternSize.height
|
|
||||||
const yEnd = yStart + patternSize.height
|
|
||||||
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.moveTo(x, yStart) // 선 시작점
|
|
||||||
ctx.lineTo(x, yEnd) // 선 끝점
|
|
||||||
ctx.stroke()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 패턴 생성
|
|
||||||
const pattern = new fabric.Pattern({
|
|
||||||
source: patternSourceCanvas,
|
|
||||||
repeat: 'repeat',
|
|
||||||
})
|
|
||||||
|
|
||||||
polygon.set('fill', null)
|
|
||||||
polygon.set('fill', pattern)
|
|
||||||
canvas?.renderAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
applySurfaceShape,
|
applySurfaceShape,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { intersect } from 'mathjs'
|
import { intersect } from 'mathjs'
|
||||||
|
import * as turf from '@turf/turf'
|
||||||
/**
|
/**
|
||||||
* Collection of function to use on canvas
|
* Collection of function to use on canvas
|
||||||
*/
|
*/
|
||||||
@ -725,3 +725,96 @@ export const getIntersectionPoint = (p1, p2, y) => {
|
|||||||
const x = (y - intercept) / slope
|
const x = (y - intercept) / slope
|
||||||
return { x, y }
|
return { x, y }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const pointsToTurfPolygon = (points) => {
|
||||||
|
const coordinates = points.map((point) => [point.x, point.y])
|
||||||
|
coordinates.push(coordinates[0])
|
||||||
|
return turf.polygon([coordinates])
|
||||||
|
}
|
||||||
|
|
||||||
|
export const polygonToTurfPolygon = (polygon) => {
|
||||||
|
const coordinates = polygon.points.map((point) => [point.x, point.y])
|
||||||
|
coordinates.push(coordinates[0])
|
||||||
|
return turf.polygon(
|
||||||
|
[coordinates],
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
parentId: polygon.parentId,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const rectToPolygon = (rect) => {
|
||||||
|
const points = []
|
||||||
|
const left = rect.left
|
||||||
|
const top = rect.top
|
||||||
|
const width = rect.width * rect.scaleX // 스케일 적용
|
||||||
|
const height = rect.height * rect.scaleY // 스케일 적용
|
||||||
|
|
||||||
|
// 네 개의 꼭짓점 좌표 계산
|
||||||
|
points.push({ x: left, y: top }) // 좌상단
|
||||||
|
points.push({ x: left + width, y: top }) // 우상단
|
||||||
|
points.push({ x: left + width, y: top + height }) // 우하단
|
||||||
|
points.push({ x: left, y: top + height }) // 좌하단
|
||||||
|
|
||||||
|
return points
|
||||||
|
}
|
||||||
|
|
||||||
|
//면형상 선택 클릭시 지붕 패턴 입히기
|
||||||
|
export function setSurfaceShapePattern(polygon) {
|
||||||
|
const ratio = window.devicePixelRatio || 1
|
||||||
|
|
||||||
|
let width = 265 / 10
|
||||||
|
let height = 150 / 10
|
||||||
|
let roofStyle = 2
|
||||||
|
const inputPatternSize = { width: width, height: height } //임시 사이즈
|
||||||
|
const patternSize = { ...inputPatternSize } // 입력된 값을 뒤집기 위해
|
||||||
|
|
||||||
|
if (polygon.direction === 'east' || polygon.direction === 'west') {
|
||||||
|
//세로형이면 width height를 바꿈
|
||||||
|
;[patternSize.width, patternSize.height] = [inputPatternSize.height, patternSize.width]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 패턴 소스를 위한 임시 캔버스 생성
|
||||||
|
const patternSourceCanvas = document.createElement('canvas')
|
||||||
|
patternSourceCanvas.width = polygon.width * ratio
|
||||||
|
patternSourceCanvas.height = polygon.height * ratio
|
||||||
|
const ctx = patternSourceCanvas.getContext('2d')
|
||||||
|
const offset = roofStyle === 1 ? 0 : patternSize.width / 2
|
||||||
|
|
||||||
|
const rows = Math.floor(patternSourceCanvas.height / patternSize.height)
|
||||||
|
const cols = Math.floor(patternSourceCanvas.width / patternSize.width)
|
||||||
|
|
||||||
|
ctx.strokeStyle = 'green'
|
||||||
|
ctx.lineWidth = 0.4
|
||||||
|
|
||||||
|
for (let row = 0; row <= rows; row++) {
|
||||||
|
const y = row * patternSize.height
|
||||||
|
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(0, y) // 선 시작점
|
||||||
|
ctx.lineTo(patternSourceCanvas.width, y) // 선 끝점
|
||||||
|
ctx.stroke()
|
||||||
|
|
||||||
|
for (let col = 0; col <= cols; col++) {
|
||||||
|
const x = col * patternSize.width + (row % 2 === 0 ? 0 : offset)
|
||||||
|
const yStart = row * patternSize.height
|
||||||
|
const yEnd = yStart + patternSize.height
|
||||||
|
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(x, yStart) // 선 시작점
|
||||||
|
ctx.lineTo(x, yEnd) // 선 끝점
|
||||||
|
ctx.stroke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 패턴 생성
|
||||||
|
const pattern = new fabric.Pattern({
|
||||||
|
source: patternSourceCanvas,
|
||||||
|
repeat: 'repeat',
|
||||||
|
})
|
||||||
|
|
||||||
|
polygon.set('fill', null)
|
||||||
|
polygon.set('fill', pattern)
|
||||||
|
polygon.canvas?.renderAll()
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user