'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, } }