1135 lines
38 KiB
JavaScript
1135 lines
38 KiB
JavaScript
'use client'
|
|
import { useEffect } 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 { useSwal } from '@/hooks/useSwal'
|
|
import * as turf from '@turf/turf'
|
|
import { usePolygon } from '@/hooks/usePolygon'
|
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
|
import { v4 as uuidv4 } from 'uuid'
|
|
import { fontSelector } from '@/store/fontAtom'
|
|
import { useRoofFn } from '@/hooks/common/useRoofFn'
|
|
|
|
export function useObjectBatch({ isHidden, setIsHidden }) {
|
|
const { getMessage } = useMessage()
|
|
const canvas = useRecoilValue(canvasState)
|
|
const { addCanvasMouseEventListener, initEvent, addDocumentEventListener } = useEvent()
|
|
// const { addCanvasMouseEventListener, initEvent, addDocumentEventListener } = useContext(EventContext)
|
|
const { swalFire } = useSwal()
|
|
const { drawDirectionArrow } = usePolygon()
|
|
const { setSurfaceShapePattern } = useRoofFn()
|
|
const lengthTextFont = useRecoilValue(fontSelector('lengthText'))
|
|
|
|
useEffect(() => {
|
|
if (canvas) {
|
|
// dbClickEvent()
|
|
}
|
|
|
|
return () => {
|
|
initEvent()
|
|
if (canvas) canvas.off('mouse:dblclick')
|
|
}
|
|
}, [])
|
|
|
|
const dbClickEvent = () => {
|
|
// console.log('dbClickEvent 실행')
|
|
const dormerObject = canvas.getObjects().filter((obj) => obj.name === BATCH_TYPE.TRIANGLE_DORMER || obj.name === BATCH_TYPE.PENTAGON_DORMER)
|
|
|
|
// console.log('dormerObject', dormerObject)
|
|
|
|
if (dormerObject) {
|
|
canvas.off('mouse:dblclick')
|
|
canvas.on('mouse:dblclick', (e) => {
|
|
console.log('event', e)
|
|
|
|
if (e.target && e.target instanceof fabric.Group) {
|
|
const pointer = canvas.getPointer(e.e)
|
|
const objects = e.target._objects
|
|
|
|
// 클릭한 위치에 있는 객체 찾기
|
|
const clickedObject = objects.find((obj) => {
|
|
if (obj.type === 'QPolygon') {
|
|
const polygon = pointsToTurfPolygon(obj.getCurrentPoints())
|
|
const turfPointer = turf.point([pointer.x, pointer.y])
|
|
return turf.booleanPointInPolygon(turfPointer, polygon)
|
|
} else {
|
|
return obj.containsPoint(pointer)
|
|
}
|
|
})
|
|
|
|
if (clickedObject) {
|
|
// 클릭된 객체 선택
|
|
canvas.setActiveObject(clickedObject)
|
|
canvas.renderAll()
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const applyOpeningAndShadow = (objectPlacement, buttonAct, surfaceShapePolygons) => {
|
|
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 objTempName = buttonAct === 1 ? BATCH_TYPE.OPENING_TEMP : BATCH_TYPE.SHADOW_TEMP
|
|
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: getMessage('batch.object.outside.roof'), icon: 'error' })
|
|
initEvent() //이벤트 초기화
|
|
if (setIsHidden) setIsHidden(false)
|
|
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: getMessage('batch.object.outside.roof'), icon: 'error' })
|
|
//일단 지워
|
|
deleteTempObjects()
|
|
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: getMessage('batch.object.notinstall.cross'), icon: 'error' })
|
|
deleteTempObjects()
|
|
return
|
|
}
|
|
}
|
|
|
|
isDown = false
|
|
rect.set({ name: objName, parentId: selectedSurface.id, points: rectToPolygon(rect) })
|
|
rect.setCoords()
|
|
initEvent()
|
|
|
|
if (setIsHidden) setIsHidden(false)
|
|
}
|
|
})
|
|
} 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,
|
|
parentId: selectedSurface.id,
|
|
})
|
|
|
|
//개구냐 그림자냐에 따라 변경
|
|
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: getMessage('batch.object.outside.roof'), icon: 'error' })
|
|
//일단 지워
|
|
deleteTempObjects()
|
|
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: getMessage('batch.object.notinstall.cross'), icon: 'error' })
|
|
deleteTempObjects()
|
|
return
|
|
}
|
|
}
|
|
|
|
isDown = false
|
|
rect.set({ name: objName, parentId: selectedSurface.id, points: rectToPolygon(rect) })
|
|
rect.setCoords()
|
|
initEvent()
|
|
if (setIsHidden) setIsHidden(false)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 오브젝트 도머 배치
|
|
* @param {} dormerPlacement
|
|
* @param {*} buttonAct
|
|
* @param {*} surfaceShapePolygons
|
|
* @returns
|
|
*/
|
|
const applyDormers = (dormerPlacement, buttonAct, surfaceShapePolygons) => {
|
|
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
|
|
let dormer, dormerOffset, isDown, selectedSurface, pentagonPoints, pentagonOffsetPoints
|
|
const id = uuidv4()
|
|
|
|
if (height === '' || pitch === '' || height <= 0 || pitch <= 0) {
|
|
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
|
|
return
|
|
}
|
|
|
|
//삼각형 도머
|
|
if (buttonAct === 3) {
|
|
const bottomLength = height / (pitch * 0.25)
|
|
const bottomOffsetLength = (height + offsetRef) / (pitch * 0.25)
|
|
|
|
addCanvasMouseEventListener('mouse:move', (e) => {
|
|
isDown = true
|
|
if (!isDown) return
|
|
|
|
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === dormerTempName)) //움직일때 일단 지워가면서 움직임
|
|
const pointer = canvas.getPointer(e.e)
|
|
|
|
surfaceShapePolygons.forEach((surface) => {
|
|
if (surface.inPolygon({ x: pointer.x, y: pointer.y })) {
|
|
selectedSurface = surface
|
|
}
|
|
})
|
|
|
|
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: 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)
|
|
|
|
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 selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
|
|
|
|
//지붕 밖으로 그렸을때
|
|
if (!turf.booleanWithin(trianglePolygon, selectedSurfacePolygon)) {
|
|
swalFire({ text: getMessage('batch.object.outside.roof'), icon: 'error' })
|
|
//일단 지워
|
|
deleteTempObjects()
|
|
return
|
|
}
|
|
|
|
//각도 추가
|
|
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 groupPoints = offsetRef > 0 ? triangleToPolygon(dormerOffset) : triangleToPolygon(dormer)
|
|
|
|
let splitedTriangle = offsetRef > 0 ? splitDormerTriangle(dormerOffset, directionRef) : splitDormerTriangle(dormer, directionRef)
|
|
canvas?.remove(offsetRef > 0 ? dormerOffset : dormer)
|
|
|
|
if (offsetRef > 0)
|
|
dormer.set({
|
|
name: dormerName,
|
|
stroke: 'black',
|
|
strokeWidth: 1,
|
|
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 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,
|
|
})
|
|
|
|
// canvas?.add(leftTriangle)
|
|
// canvas?.add(rightTriangle)
|
|
|
|
//패턴
|
|
setSurfaceShapePattern(leftTriangle)
|
|
setSurfaceShapePattern(rightTriangle)
|
|
//방향
|
|
|
|
// drawDirectionArrow(leftTriangle)
|
|
// drawDirectionArrow(rightTriangle)
|
|
|
|
let offsetPolygon
|
|
|
|
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,
|
|
})
|
|
}
|
|
|
|
const groupPolygon = offsetPolygon ? [leftTriangle, rightTriangle, offsetPolygon] : [leftTriangle, rightTriangle]
|
|
|
|
const objectGroup = new fabric.Group(groupPolygon, {
|
|
subTargetCheck: true,
|
|
name: dormerName,
|
|
id: id,
|
|
parentId: selectedSurface.id,
|
|
originX: 'center',
|
|
originY: 'center',
|
|
groupPoints: groupPoints,
|
|
})
|
|
canvas?.add(objectGroup)
|
|
|
|
objectGroup.getObjects().forEach((obj, index) => {
|
|
console.log(`최초 pathOffset ${index}`, obj.get('pathOffset'))
|
|
})
|
|
|
|
isDown = false
|
|
initEvent()
|
|
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
|
|
|
|
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === dormerTempName)) //움직일때 일단 지워가면서 움직임
|
|
const pointer = canvas.getPointer(e.e)
|
|
|
|
surfaceShapePolygons.forEach((surface) => {
|
|
if (surface.inPolygon({ x: pointer.x, y: pointer.y })) {
|
|
selectedSurface = surface
|
|
}
|
|
})
|
|
|
|
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 - 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) },
|
|
]
|
|
|
|
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 },
|
|
]
|
|
|
|
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)
|
|
|
|
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 selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
|
|
|
|
//지붕 밖으로 그렸을때
|
|
if (!turf.booleanWithin(pentagonPolygon, selectedSurfacePolygon)) {
|
|
swalFire({ text: getMessage('batch.object.outside.roof'), icon: 'error' })
|
|
//일단 지워
|
|
deleteTempObjects()
|
|
return
|
|
}
|
|
|
|
//각도 추가
|
|
|
|
let direction = 'south'
|
|
if (directionRef === 'left') {
|
|
//서
|
|
direction = 'west'
|
|
} else if (directionRef === 'right') {
|
|
//동
|
|
direction = 'east'
|
|
} else if (directionRef === 'up') {
|
|
//북
|
|
direction = 'north'
|
|
}
|
|
|
|
const offsetMode = offsetRef > 0 || offsetWidthRef > 0 ? 'offset' : 'normal'
|
|
let splitedPentagon =
|
|
offsetRef > 0 || offsetWidthRef > 0
|
|
? splitDormerPentagon(dormerOffset, directionRef, offsetMode)
|
|
: splitDormerPentagon(dormer, directionRef, offsetMode)
|
|
canvas?.remove(offsetRef > 0 || offsetWidthRef > 0 ? dormerOffset : dormer)
|
|
|
|
if (offsetRef > 0)
|
|
dormer.set({
|
|
name: dormerName,
|
|
stroke: 'black',
|
|
strokeWidth: 1,
|
|
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 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,
|
|
})
|
|
|
|
// canvas?.add(leftPentagon)
|
|
// canvas?.add(rightPentagon)
|
|
|
|
//패턴
|
|
setSurfaceShapePattern(leftPentagon)
|
|
setSurfaceShapePattern(rightPentagon)
|
|
//방향
|
|
// drawDirectionArrow(leftPentagon)
|
|
// drawDirectionArrow(rightPentagon)
|
|
|
|
let offsetPolygon
|
|
|
|
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,
|
|
})
|
|
}
|
|
|
|
const groupPolygon = offsetPolygon ? [leftPentagon, rightPentagon, offsetPolygon] : [leftPentagon, rightPentagon]
|
|
const groupPoints = offsetRef > 0 ? pentagonOffsetPoints : pentagonPoints
|
|
|
|
const objectGroup = new fabric.Group(groupPolygon, {
|
|
subTargetCheck: true,
|
|
name: dormerName,
|
|
id: id,
|
|
parentId: selectedSurface.id,
|
|
groupYn: true,
|
|
originX: 'center',
|
|
originY: 'center',
|
|
groupPoints: groupPoints,
|
|
})
|
|
canvas?.add(objectGroup)
|
|
|
|
isDown = false
|
|
initEvent()
|
|
|
|
dbClickEvent()
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const deleteTempObjects = () => {
|
|
const deleteTarget = canvas
|
|
?.getObjects()
|
|
.filter(
|
|
(obj) =>
|
|
obj.name === BATCH_TYPE.OPENING_TEMP ||
|
|
obj.name === BATCH_TYPE.SHADOW_TEMP ||
|
|
obj.name === BATCH_TYPE.TRIANGLE_DORMER_TEMP ||
|
|
obj.name === BATCH_TYPE.PENTAGON_DORMER_TEMP,
|
|
)
|
|
canvas?.remove(...deleteTarget)
|
|
initEvent() //이벤트 초기화
|
|
if (setIsHidden) setIsHidden(false)
|
|
}
|
|
|
|
const splitDormerTriangle = (triangle, direction) => {
|
|
const halfWidth = triangle.width / 2
|
|
|
|
let leftPoints = []
|
|
let rightPoints = []
|
|
|
|
if (direction === 'down') {
|
|
leftPoints = [
|
|
{ x: triangle.left, y: triangle.top },
|
|
{ x: triangle.left - halfWidth, y: triangle.top + triangle.height },
|
|
{ x: triangle.left, y: triangle.top + triangle.height },
|
|
]
|
|
|
|
rightPoints = [
|
|
{ x: triangle.left, y: triangle.top },
|
|
{ x: triangle.left, 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 },
|
|
{ x: triangle.left - halfWidth, y: triangle.top - triangle.height },
|
|
{ x: triangle.left, y: triangle.top - triangle.height },
|
|
]
|
|
|
|
rightPoints = [
|
|
{ x: triangle.left, y: triangle.top },
|
|
{ x: triangle.left, 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 },
|
|
{ x: triangle.left - triangle.height, y: triangle.top - halfWidth },
|
|
{ x: triangle.left - triangle.height, y: triangle.top },
|
|
]
|
|
|
|
rightPoints = [
|
|
{ x: triangle.left, y: triangle.top },
|
|
{ x: triangle.left - triangle.height, y: triangle.top },
|
|
{ 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 },
|
|
{ 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 },
|
|
]
|
|
}
|
|
return [leftPoints, rightPoints]
|
|
}
|
|
|
|
const splitDormerPentagon = (pentagon, direction, offsetMode) => {
|
|
const points = pentagon.points
|
|
|
|
let leftPoints = []
|
|
let rightPoints = []
|
|
|
|
if (direction === 'down') {
|
|
leftPoints = [
|
|
{ x: points[0].x, y: points[0].y },
|
|
{ x: points[1].x, y: points[1].y },
|
|
{ x: points[2].x, y: points[2].y },
|
|
{ x: points[0].x, y: points[3].y },
|
|
]
|
|
|
|
rightPoints = [
|
|
{ x: points[0].x, y: points[0].y },
|
|
{ x: points[0].x, y: points[2].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 },
|
|
{ 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[0].x, y: points[0].y - (points[2].y - points[0].y) },
|
|
]
|
|
|
|
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) },
|
|
]
|
|
} else if (direction === 'left') {
|
|
leftPoints = [
|
|
{ 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 },
|
|
]
|
|
|
|
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 + (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 },
|
|
]
|
|
} else if (direction === 'right') {
|
|
leftPoints = [
|
|
{ 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 },
|
|
]
|
|
|
|
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 - (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 },
|
|
]
|
|
}
|
|
|
|
return [leftPoints, rightPoints]
|
|
}
|
|
|
|
const resizeObjectBatch = (side, target, width, height) => {
|
|
const objectWidth = target.width
|
|
const objectHeight = target.height
|
|
const changeWidth = (width / 10 / objectWidth).toFixed(2)
|
|
const changeHeight = (height / 10 / objectHeight).toFixed(2)
|
|
let sideX = 'left'
|
|
let sideY = 'top'
|
|
|
|
//그룹 중심점 변경
|
|
if (side === 2) {
|
|
sideX = 'right'
|
|
sideY = 'top'
|
|
} else if (side === 3) {
|
|
sideX = 'left'
|
|
sideY = 'bottom'
|
|
} else if (side === 4) {
|
|
sideX = 'right'
|
|
sideY = 'bottom'
|
|
}
|
|
|
|
//변경 전 좌표
|
|
const newCoords = target.getPointByOrigin(sideX, sideY)
|
|
|
|
target.set({
|
|
originX: sideX,
|
|
originY: sideY,
|
|
left: newCoords.x,
|
|
top: newCoords.y,
|
|
})
|
|
|
|
target.setCoords()
|
|
canvas?.renderAll() //변경 좌표를 한번 적용
|
|
|
|
target.scaleX = changeWidth || 1
|
|
target.scaleY = changeHeight || 1
|
|
|
|
//크기 변경후 좌표를 재 적용
|
|
const changedCoords = target.getPointByOrigin('center', 'center')
|
|
|
|
target.set({
|
|
...target,
|
|
originX: 'center',
|
|
originY: 'center',
|
|
left: changedCoords.x,
|
|
top: changedCoords.y,
|
|
width: width / 10,
|
|
height: height / 10,
|
|
})
|
|
|
|
//얘는 일단 도머에 적용함
|
|
if (target.type === 'group') {
|
|
target._objects.forEach((obj) => setSurfaceShapePattern(obj))
|
|
}
|
|
|
|
// target.setCoords()
|
|
canvas.renderAll()
|
|
if (target.type === 'group') reGroupObject(target)
|
|
}
|
|
|
|
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: [],
|
|
})
|
|
reGroupObjects.push(newObj)
|
|
canvas.remove(obj)
|
|
if (newObj.direction) {
|
|
drawDirectionArrow(newObj)
|
|
}
|
|
newObj.fire('modified')
|
|
})
|
|
const reGroup = new fabric.Group(reGroupObjects, {
|
|
subTargetCheck: true,
|
|
name: groupObj.name,
|
|
id: groupObj.id,
|
|
groupYn: true,
|
|
parentId: groupObj.parentId,
|
|
originX: 'center',
|
|
originY: 'center',
|
|
})
|
|
canvas?.add(reGroup)
|
|
canvas?.remove(groupObj)
|
|
|
|
return reGroup
|
|
}
|
|
|
|
const moveObjectBatch = () => {
|
|
const obj = canvas.getActiveObject()
|
|
const parentSurface = canvas?.getObjects().filter((item) => item.name === POLYGON_TYPE.ROOF && item.id === obj.parentId)[0]
|
|
|
|
if (obj) {
|
|
obj.set({
|
|
lockMovementX: false,
|
|
lockMovementY: false,
|
|
})
|
|
|
|
const originObj = { ...obj }
|
|
addCanvasMouseEventListener('mouse:up', (e) => {
|
|
//개구, 그림자 타입일 경우 폴리곤 타입 변경
|
|
if (BATCH_TYPE.OPENING === obj.name || BATCH_TYPE.SHADOW === obj.name) {
|
|
obj.set({
|
|
points: rectToPolygon(obj),
|
|
})
|
|
|
|
const turfSurface = pointsToTurfPolygon(parentSurface.points)
|
|
const turfObject = pointsToTurfPolygon(obj.points)
|
|
|
|
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,
|
|
})
|
|
|
|
if (obj.type === 'group') reGroupObject(obj)
|
|
obj.setCoords()
|
|
}
|
|
canvas.discardActiveObject()
|
|
initEvent()
|
|
})
|
|
}
|
|
}
|
|
|
|
const copyObjectBatch = () => {
|
|
const obj = canvas.getActiveObject()
|
|
if (obj) {
|
|
let clonedObj = null
|
|
const parentSurface = canvas?.getObjects().filter((item) => item.name === POLYGON_TYPE.ROOF && item.id === obj.parentId)[0]
|
|
|
|
obj.clone((cloned) => {
|
|
clonedObj = cloned
|
|
})
|
|
|
|
addCanvasMouseEventListener('mouse:move', (e) => {
|
|
const pointer = canvas?.getPointer(e.e)
|
|
if (!clonedObj) return
|
|
|
|
canvas
|
|
.getObjects()
|
|
.filter((clonedObj) => clonedObj.name === 'clonedObj')
|
|
.forEach((clonedObj) => canvas?.remove(clonedObj))
|
|
|
|
clonedObj.set({
|
|
left: pointer.x,
|
|
top: pointer.y,
|
|
name: 'clonedObj',
|
|
})
|
|
canvas.add(clonedObj)
|
|
})
|
|
|
|
addCanvasMouseEventListener('mouse:up', (e) => {
|
|
//개구, 그림자 타입일 경우 폴리곤 타입 변경
|
|
if (BATCH_TYPE.OPENING == obj.name || BATCH_TYPE.SHADOW == obj.name) {
|
|
clonedObj.set({
|
|
points: rectToPolygon(clonedObj),
|
|
})
|
|
|
|
const turfSurface = pointsToTurfPolygon(parentSurface.points)
|
|
const turfObject = pointsToTurfPolygon(clonedObj.points)
|
|
|
|
if (turf.booleanWithin(turfObject, turfSurface)) {
|
|
clonedObj.set({
|
|
lockMovementX: true,
|
|
lockMovementY: true,
|
|
name: BATCH_TYPE.OPENING,
|
|
parentId: parentSurface.id,
|
|
})
|
|
clonedObj.setCoords()
|
|
} else {
|
|
swalFire({
|
|
title: getMessage('batch.object.outside.roof'),
|
|
icon: 'warning',
|
|
})
|
|
canvas.remove(clonedObj)
|
|
}
|
|
} else {
|
|
clonedObj.set({
|
|
lockMovementX: true,
|
|
lockMovementY: true,
|
|
name: obj.name,
|
|
})
|
|
|
|
if (clonedObj.type === 'group') reGroupObject(clonedObj)
|
|
clonedObj.setCoords()
|
|
}
|
|
canvas.discardActiveObject()
|
|
initEvent()
|
|
})
|
|
}
|
|
}
|
|
|
|
const dormerOffsetKeyEvent = (setArrow1, setArrow2) => {
|
|
addDocumentEventListener('keydown', document, (e) => {
|
|
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
|
|
const keyEvent = e.key === 'ArrowDown' ? 'down' : 'up'
|
|
setArrow1(keyEvent)
|
|
} else if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
|
|
const keyEvent = e.key === 'ArrowLeft' ? 'left' : 'right'
|
|
setArrow2(keyEvent)
|
|
}
|
|
})
|
|
}
|
|
|
|
const dormerOffset = (arrow1, arrow2, length1, length2) => {
|
|
length1 = parseInt(length1) / 10
|
|
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
|
|
|
|
if (dormer.type === 'group') {
|
|
const newDormer = reGroupObject(dormer)
|
|
canvas?.setActiveObject(newDormer)
|
|
}
|
|
canvas.renderAll()
|
|
}
|
|
|
|
return {
|
|
applyOpeningAndShadow,
|
|
applyDormers,
|
|
splitDormerTriangle,
|
|
splitDormerPentagon,
|
|
resizeObjectBatch,
|
|
moveObjectBatch,
|
|
dormerOffsetKeyEvent,
|
|
dormerOffset,
|
|
copyObjectBatch,
|
|
}
|
|
}
|