211 lines
7.0 KiB
JavaScript
211 lines
7.0 KiB
JavaScript
'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() {
|
|
const { getMessage } = useMessage()
|
|
const canvas = useRecoilValue(canvasState)
|
|
const { addCanvasMouseEventListener, initEvent } = useEvent()
|
|
const { swalFire } = useSwal()
|
|
|
|
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,
|
|
}
|
|
}
|