915 lines
28 KiB
JavaScript
915 lines
28 KiB
JavaScript
import { useEffect } from 'react'
|
|
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
|
|
import { wordDisplaySelector } from '@/store/settingAtom'
|
|
import { useEvent } from '@/hooks/useEvent'
|
|
import { checkLineOrientation, getDistance } from '@/util/canvas-util'
|
|
import { commonUtilsState, dimensionLineSettingsState } from '@/store/commonUtilsAtom'
|
|
import { fontSelector } from '@/store/fontAtom'
|
|
import { canvasState, currentMenuState } from '@/store/canvasAtom'
|
|
import { v4 as uuidv4 } from 'uuid'
|
|
import { usePopup } from '@/hooks/usePopup'
|
|
import Distance from '@/components/floor-plan/modal/distance/Distance'
|
|
import { usePolygon } from '@/hooks/usePolygon'
|
|
import { useObjectBatch } from '@/hooks/object/useObjectBatch'
|
|
import { BATCH_TYPE } from '@/common/common'
|
|
|
|
export function useCommonUtils() {
|
|
const canvas = useRecoilValue(canvasState)
|
|
const wordDisplay = useRecoilValue(wordDisplaySelector)
|
|
const { addCanvasMouseEventListener, addDocumentEventListener, initEvent, removeMouseEvent } = useEvent()
|
|
const dimensionSettings = useRecoilValue(dimensionLineSettingsState)
|
|
const dimensionLineTextFont = useRecoilValue(fontSelector('dimensionLineText'))
|
|
const lengthTextFont = useRecoilValue(fontSelector('lengthText'))
|
|
const commonTextFont = useRecoilValue(fontSelector('commonText'))
|
|
const [commonUtils, setCommonUtilsState] = useRecoilState(commonUtilsState)
|
|
const { addPopup, closeAll, targetClose } = usePopup()
|
|
const { drawDirectionArrow, addLengthText } = usePolygon()
|
|
const { applyDormers } = useObjectBatch({})
|
|
|
|
useEffect(() => {
|
|
commonTextMode()
|
|
if (commonUtils.dimension) {
|
|
commonDimensionMode()
|
|
return
|
|
}
|
|
if (commonUtils.distance) {
|
|
commonDistanceMode()
|
|
return
|
|
}
|
|
}, [commonUtils, dimensionSettings, commonTextFont, dimensionLineTextFont])
|
|
|
|
const commonTextMode = () => {
|
|
let textbox
|
|
|
|
if (commonUtils.text) {
|
|
targetClose('other')
|
|
setTimeout(() => {
|
|
commonTextKeyEvent()
|
|
addCanvasMouseEventListener('mouse:down', (event) => {
|
|
const pointer = canvas?.getPointer(event.e)
|
|
|
|
textbox = new fabric.Textbox('', {
|
|
left: pointer.x,
|
|
top: pointer.y,
|
|
width: 200,
|
|
editable: true,
|
|
name: 'commonText',
|
|
visible: wordDisplay,
|
|
fill: commonTextFont.fontColor.value,
|
|
fontFamily: commonTextFont.fontFamily.value,
|
|
fontSize: commonTextFont.fontSize.value,
|
|
fontStyle: commonTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
|
|
fontWeight: commonTextFont.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
|
|
selectable: true,
|
|
lockMovementX: true,
|
|
lockMovementY: true,
|
|
originX: 'center',
|
|
originY: 'center',
|
|
})
|
|
|
|
canvas?.add(textbox)
|
|
canvas.setActiveObject(textbox)
|
|
textbox.enterEditing()
|
|
textbox.selectAll()
|
|
})
|
|
}, 100)
|
|
} else {
|
|
removeMouseEvent('mouse:down')
|
|
const activeObject = canvas?.getActiveObject()
|
|
const commonTexts = canvas?.getObjects().filter((obj) => obj.name === 'commonText')
|
|
if (commonTexts) {
|
|
commonTexts.forEach((text) => {
|
|
if (text.text === '') {
|
|
canvas?.remove(text)
|
|
}
|
|
})
|
|
}
|
|
/*if (activeObject && activeObject.name === 'commonText') {
|
|
if (activeObject && activeObject.isEditing) {
|
|
if (activeObject.text === '') {
|
|
canvas?.remove(activeObject)
|
|
} else {
|
|
activeObject.exitEditing()
|
|
}
|
|
//정책 협의
|
|
const texts = canvas.getObjects().filter((obj) => obj.name === 'commonText')
|
|
texts.forEach((text) => {
|
|
text.set({ editable: false })
|
|
})
|
|
canvas.renderAll()
|
|
}
|
|
}*/
|
|
|
|
initEvent()
|
|
}
|
|
}
|
|
|
|
const createDimensionArrow = (x, y, angle, id) => {
|
|
return new fabric.Triangle({
|
|
left: x,
|
|
top: y,
|
|
originX: 'center',
|
|
originY: 'center',
|
|
angle: angle,
|
|
width: 15,
|
|
height: 15,
|
|
fill: dimensionSettings.color,
|
|
selectable: true,
|
|
name: 'arrow',
|
|
id: id,
|
|
})
|
|
}
|
|
|
|
const createDimensionExtendLine = (line, lineDirection, extendLength) => {
|
|
let extendLine = []
|
|
|
|
const extendLineLength = extendLength ? extendLength : 0
|
|
|
|
if (lineDirection === 'horizontal') {
|
|
if (extendLineLength >= 0) {
|
|
extendLine = [
|
|
[line.x1, line.y1 - 20 - extendLineLength, line.x1, line.y1 + 20],
|
|
[line.x2, line.y2 - 20 - extendLineLength, line.x2, line.y2 + 20],
|
|
]
|
|
} else {
|
|
extendLine = [
|
|
[line.x1, line.y1 + 20 - extendLineLength, line.x1, line.y1 - 20],
|
|
[line.x2, line.y2 + 20 - extendLineLength, line.x2, line.y2 - 20],
|
|
]
|
|
}
|
|
} else {
|
|
if (extendLineLength >= 0) {
|
|
extendLine = [
|
|
[line.x1 - 20 - extendLineLength, line.y1, line.x1 + 20, line.y1],
|
|
[line.x2 - 20 - extendLineLength, line.y2, line.x2 + 20, line.y2],
|
|
]
|
|
} else {
|
|
extendLine = [
|
|
[line.x1 - 20 - extendLineLength, line.y1, line.x1 - 20, line.y1],
|
|
[line.x2 - 20 - extendLineLength, line.y2, line.x2 - 20, line.y2],
|
|
]
|
|
}
|
|
}
|
|
|
|
return extendLine
|
|
}
|
|
|
|
const calcDimensionPosition = (lineDirection, p1CenterX, p1CenterY, p2CenterX, p2CenterY) => {
|
|
// 첫 번째 포인트에 화살표 추가 좌측 -> 우측으로 그릴때
|
|
let paddingX = lineDirection === 'horizontal' ? p1CenterX + 7.5 : p1CenterX + 0.5
|
|
let paddingX2 = lineDirection === 'horizontal' ? p2CenterX - 7.5 : p2CenterX + 0.5
|
|
let paddingY = lineDirection === 'horizontal' ? p1CenterY + 0.5 : p1CenterY + 8
|
|
let paddingY2 = lineDirection === 'horizontal' ? p2CenterY + 0.5 : p2CenterY - 8
|
|
let angle1 = lineDirection === 'horizontal' ? -90 : 0
|
|
let angle2 = lineDirection === 'horizontal' ? 90 : 180
|
|
|
|
// 우측 -> 좌측으로 그릴땐 반대
|
|
if (paddingX > paddingX2 || paddingY > paddingY2) {
|
|
paddingX = lineDirection === 'horizontal' ? p1CenterX - 7.5 : p1CenterX + 0.5
|
|
paddingX2 = lineDirection === 'horizontal' ? p2CenterX + 7.5 : p2CenterX + 0.5
|
|
paddingY = lineDirection === 'horizontal' ? p1CenterY + 0.5 : p1CenterY - 7.5
|
|
paddingY2 = lineDirection === 'horizontal' ? p2CenterY + 0.5 : p2CenterY + 7.5
|
|
angle1 = lineDirection === 'horizontal' ? 90 : 180
|
|
angle2 = lineDirection === 'horizontal' ? 270 : 0
|
|
}
|
|
|
|
return {
|
|
paddingX,
|
|
paddingX2,
|
|
paddingY,
|
|
paddingY2,
|
|
angle1,
|
|
angle2,
|
|
}
|
|
}
|
|
|
|
const commonDimensionMode = () => {
|
|
if (commonUtils.dimension) {
|
|
const uuid = uuidv4()
|
|
|
|
let points = []
|
|
let distanceText = null
|
|
let minX, minY, maxX, maxY
|
|
|
|
// 화살표를 생성하는 함수
|
|
|
|
const circleOptions = {
|
|
radius: 5,
|
|
strokeWidth: 2,
|
|
stroke: 'red',
|
|
fill: 'white',
|
|
selectable: true,
|
|
}
|
|
|
|
const lineOptions = {
|
|
stroke: dimensionSettings.color,
|
|
strokeWidth: dimensionSettings.pixel,
|
|
selectable: true,
|
|
originX: 'center',
|
|
originY: 'center',
|
|
}
|
|
|
|
// 캔버스에 클릭 이벤트 추가
|
|
addCanvasMouseEventListener('mouse:down', (e) => {
|
|
let groupObjects = []
|
|
|
|
const pointer = canvas.getPointer(e.e)
|
|
|
|
let point
|
|
|
|
if (points.length === 0) {
|
|
// 첫 번째 포인트는 그대로 클릭한 위치에 추가
|
|
point = new fabric.Circle({
|
|
left: pointer.x - 5, // 반지름 반영
|
|
top: pointer.y - 5, // 반지름 반영
|
|
...circleOptions,
|
|
})
|
|
points.push(point)
|
|
canvas.add(point)
|
|
} else if (points.length === 1) {
|
|
// 두 번째 포인트는 첫 번째 포인트를 기준으로 수평 또는 수직으로만 배치
|
|
const p1 = points[0]
|
|
const deltaX = Math.abs(pointer.x - (p1.left + p1.radius))
|
|
const deltaY = Math.abs(pointer.y - (p1.top + p1.radius))
|
|
|
|
if (deltaX > deltaY) {
|
|
// 수평선 상에만 배치 (y 좌표 고정)
|
|
point = new fabric.Circle({
|
|
left: pointer.x - 5, // 반지름 반영
|
|
top: p1.top, // y 좌표 고정
|
|
...circleOptions,
|
|
})
|
|
} else {
|
|
// 수직선 상에만 배치 (x 좌표 고정)
|
|
point = new fabric.Circle({
|
|
left: p1.left, // x 좌표 고정
|
|
top: pointer.y - 5, // 반지름 반영
|
|
...circleOptions,
|
|
})
|
|
}
|
|
|
|
points.push(point)
|
|
canvas.add(point)
|
|
|
|
// 두 포인트의 중심 좌표 계산
|
|
const p2 = points[1]
|
|
const p1CenterX = p1.left + p1.radius
|
|
const p1CenterY = p1.top + p1.radius
|
|
const p2CenterX = p2.left + p2.radius
|
|
const p2CenterY = p2.top + p2.radius
|
|
|
|
points.forEach((point) => {
|
|
canvas?.remove(point)
|
|
})
|
|
|
|
// 두 포인트 간에 직선을 그림 (중심을 기준으로)
|
|
const line = new fabric.Line([p1CenterX, p1CenterY, p2CenterX, p2CenterY], {
|
|
...lineOptions,
|
|
name: 'centerLine',
|
|
id: uuid,
|
|
})
|
|
// canvas.add(line)
|
|
|
|
groupObjects.push(line)
|
|
|
|
const distance = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY)
|
|
const lineDirection = checkLineOrientation(line)
|
|
|
|
const extendListArray = createDimensionExtendLine(line, lineDirection)
|
|
|
|
extendListArray.forEach((line) => {
|
|
const extendLine = new fabric.Line(line, {
|
|
...lineOptions,
|
|
name: 'extendLine',
|
|
id: uuid,
|
|
})
|
|
groupObjects.push(extendLine)
|
|
})
|
|
|
|
const dimensionPosition = calcDimensionPosition(lineDirection, p1CenterX, p1CenterY, p2CenterX, p2CenterY)
|
|
const arrow1 = createDimensionArrow(dimensionPosition.paddingX, dimensionPosition.paddingY, dimensionPosition.angle1, uuid) // 반대 방향 화살표
|
|
const arrow2 = createDimensionArrow(dimensionPosition.paddingX2, dimensionPosition.paddingY2, dimensionPosition.angle2, uuid) // 정방향 화살표
|
|
|
|
groupObjects.push(arrow1, arrow2)
|
|
|
|
distanceText = new fabric.Text(`${distance * 10} `, {
|
|
left: (p1CenterX + p2CenterX) / 2 + (lineDirection === 'horizontal' ? 0 : -15),
|
|
top: (p1CenterY + p2CenterY) / 2 + (lineDirection === 'horizontal' ? +15 : 0),
|
|
fill: dimensionLineTextFont.fontColor.value,
|
|
fontSize: dimensionLineTextFont.fontSize.value,
|
|
fontFamily: dimensionLineTextFont.fontFamily.value,
|
|
fontStyle: dimensionLineTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
|
|
fontWeight: dimensionLineTextFont.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
|
|
selectable: true,
|
|
textAlign: 'center',
|
|
originX: 'center',
|
|
originY: 'center',
|
|
angle: lineDirection === 'horizontal' ? 0 : 270,
|
|
name: 'dimensionLineText',
|
|
id: uuid,
|
|
// lockMovementX: false,
|
|
// lockMovementY: false,
|
|
})
|
|
// canvas.add(distanceText)
|
|
groupObjects.push(distanceText)
|
|
|
|
const group = new fabric.Group(groupObjects, {
|
|
name: 'dimensionGroup',
|
|
selectable: true,
|
|
originX: 'center',
|
|
originY: 'center',
|
|
lineDirection: lineDirection,
|
|
groupId: uuid,
|
|
length: distance * 10,
|
|
slopeAble: false,
|
|
angle1: null,
|
|
angle2: null,
|
|
})
|
|
|
|
canvas.add(group)
|
|
|
|
// groupObjects.push(distanceText)
|
|
|
|
canvas.renderAll()
|
|
|
|
// 거리 계산 후, 다음 측정을 위해 초기화
|
|
points = []
|
|
|
|
if (setCommonUtilsState)
|
|
setCommonUtilsState({
|
|
...commonUtilsState,
|
|
dimension: false,
|
|
})
|
|
|
|
initEvent()
|
|
}
|
|
|
|
// 캔버스 다시 그리기
|
|
canvas.renderAll()
|
|
})
|
|
}
|
|
}
|
|
|
|
const commonDistanceMode = () => {
|
|
if (commonUtils.distance) {
|
|
let points = []
|
|
let distanceText = null
|
|
let drawPoints = []
|
|
|
|
const crossOptions = {
|
|
stroke: 'black',
|
|
strokeWidth: 1,
|
|
originX: 'center',
|
|
originY: 'center',
|
|
name: 'distance',
|
|
}
|
|
|
|
const lineOptions = {
|
|
stroke: 'black',
|
|
strokeWidth: 1,
|
|
selectable: false,
|
|
strokeDashArray: [10, 5],
|
|
name: 'distance',
|
|
}
|
|
|
|
const textOptions = {
|
|
fill: 'black',
|
|
fontSize: 16,
|
|
selectable: true,
|
|
textAlign: 'center',
|
|
originX: 'center',
|
|
originY: 'center',
|
|
name: 'distance',
|
|
}
|
|
|
|
// 캔버스에 클릭 이벤트 추가
|
|
addCanvasMouseEventListener('mouse:down', function (e) {
|
|
const pointer = canvas.getPointer(e.e)
|
|
let point
|
|
let cross = {}
|
|
|
|
if (points.length === 0) {
|
|
point = new fabric.Line([pointer.x - 10, pointer.y, pointer.x + 10, pointer.y], crossOptions)
|
|
canvas.add(point)
|
|
cross['x'] = parseInt(point.left.toFixed(0))
|
|
drawPoints.push(point)
|
|
|
|
// 세로 선 생성 (십자 모양의 다른 축)
|
|
point = new fabric.Line([pointer.x, pointer.y - 10, pointer.x, pointer.y + 10], crossOptions)
|
|
cross['y'] = parseInt(point.top.toFixed(0))
|
|
drawPoints.push(point)
|
|
|
|
canvas.add(point)
|
|
points.push(cross)
|
|
} else if (points.length === 1) {
|
|
// 두 번째 포인트는 첫 번째 포인트를 기준으로 수평 또는 수직으로만 배치
|
|
const p1 = points[0]
|
|
|
|
point = new fabric.Line([pointer.x - 10, pointer.y, pointer.x + 10, pointer.y], crossOptions)
|
|
canvas.add(point)
|
|
cross['x'] = parseInt(point.left.toFixed(0))
|
|
drawPoints.push(point)
|
|
// 세로 선 생성 (십자 모양의 다른 축)
|
|
point = new fabric.Line([pointer.x, pointer.y - 10, pointer.x, pointer.y + 10], crossOptions)
|
|
canvas.add(point)
|
|
cross['y'] = parseInt(point.top.toFixed(0))
|
|
drawPoints.push(point)
|
|
points.push(cross)
|
|
|
|
let isParallel = false
|
|
|
|
if (points[0].x === points[1].x || points[0].y === points[1].y) {
|
|
isParallel = true
|
|
}
|
|
|
|
// 두 포인트의 중심 좌표 계산
|
|
const p2 = points[1]
|
|
|
|
const p1CenterX = p1.x
|
|
const p1CenterY = p1.y
|
|
const p2CenterX = p2.x
|
|
const p2CenterY = p2.y
|
|
|
|
// 두 포인트 간에 직선을 그림 (중심을 기준으로)
|
|
const line = new fabric.Line([p1CenterX, p1CenterY, p2CenterX, p2CenterY], lineOptions)
|
|
canvas.add(line)
|
|
const distance1 = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY)
|
|
|
|
// 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성
|
|
distanceText = new fabric.Text(`${distance1 * 10}`, {
|
|
left: (p1CenterX + p2CenterX) / 2,
|
|
top: (p1CenterY + p2CenterY) / 2,
|
|
...textOptions,
|
|
})
|
|
canvas.add(distanceText)
|
|
|
|
let distance2 = 0
|
|
let distance3 = 0
|
|
if (!isParallel) {
|
|
const p3 = new fabric.Point(p2CenterX, p1CenterY)
|
|
const line2 = new fabric.Line([p2CenterX, p2CenterY, p3.x, p3.y], lineOptions)
|
|
const line3 = new fabric.Line([p3.x, p3.y, p1CenterX, p1CenterY], lineOptions)
|
|
canvas.add(line2)
|
|
canvas.add(line3)
|
|
distance2 = getDistance(p2CenterX, p2CenterY, p3.x, p3.y)
|
|
distance3 = getDistance(p3.x, p3.y, p1CenterX, p1CenterY)
|
|
distanceText = new fabric.Text(`${distance2 * 10}`, {
|
|
left: (p2CenterX + p3.x) / 2,
|
|
top: (p2CenterY + p3.y) / 2,
|
|
...textOptions,
|
|
})
|
|
canvas.add(distanceText)
|
|
distanceText = new fabric.Text(`${distance3 * 10}`, {
|
|
left: (p3.x + p1CenterX) / 2,
|
|
top: (p3.y + p1CenterY) / 2,
|
|
...textOptions,
|
|
})
|
|
canvas.add(distanceText)
|
|
}
|
|
|
|
const id = uuidv4()
|
|
addPopup(
|
|
id,
|
|
1,
|
|
<Distance
|
|
id={id}
|
|
distance={{
|
|
horizon: distance3 * 10,
|
|
vertical: distance2 * 10,
|
|
diagonal: distance1 * 10,
|
|
}}
|
|
deleteDistance={closeDistancePopup}
|
|
/>,
|
|
)
|
|
|
|
if (setCommonUtilsState)
|
|
setCommonUtilsState({
|
|
...commonUtils,
|
|
distance: false,
|
|
})
|
|
|
|
// 거리 계산 후, 다음 측정을 위해 초기화
|
|
points = []
|
|
}
|
|
|
|
// 캔버스 다시 그리기
|
|
canvas.renderAll()
|
|
})
|
|
}
|
|
}
|
|
|
|
const commonTextKeyEvent = () => {
|
|
//텍스트 모드일때 엔터 이벤트
|
|
addDocumentEventListener('keydown', document, (e) => {
|
|
if (e.key === 'Enter') {
|
|
const activeObject = canvas.getActiveObject()
|
|
if (activeObject && activeObject.name === 'commonText') {
|
|
if (activeObject && activeObject.isEditing) {
|
|
if (activeObject.text === '') {
|
|
canvas?.remove(activeObject)
|
|
} else {
|
|
activeObject.exitEditing()
|
|
}
|
|
//정책 협의
|
|
const texts = canvas.getObjects().filter((obj) => obj.name === 'commonText')
|
|
texts.forEach((text) => {
|
|
text.set({ editable: false })
|
|
})
|
|
|
|
canvas.renderAll()
|
|
if (setCommonUtilsState) setCommonUtilsState({ ...commonUtils, text: false })
|
|
}
|
|
}
|
|
initEvent()
|
|
}
|
|
})
|
|
}
|
|
|
|
const commonFunctions = (mode) => {
|
|
let tempStates = { ...commonUtils }
|
|
|
|
if (tempStates[mode]) {
|
|
tempStates[mode] = false
|
|
} else {
|
|
Object.keys(tempStates).forEach((key) => {
|
|
tempStates[key] = false
|
|
})
|
|
|
|
if (mode !== undefined) {
|
|
tempStates[mode] = true
|
|
}
|
|
}
|
|
|
|
if (setCommonUtilsState) setCommonUtilsState(tempStates)
|
|
}
|
|
|
|
const commonDeleteText = (object) => {
|
|
if (object) {
|
|
canvas?.remove(object)
|
|
|
|
if (object.id) {
|
|
const group = canvas.getObjects().filter((obj) => obj.id === object.id)
|
|
group.forEach((obj) => canvas?.remove(obj))
|
|
}
|
|
|
|
if (object.type === 'group') {
|
|
object._objects.forEach((obj) => {
|
|
if (obj.hasOwnProperty('texts')) {
|
|
obj.texts.forEach((text) => {
|
|
canvas?.remove(text)
|
|
})
|
|
}
|
|
})
|
|
} else {
|
|
if (object.hasOwnProperty('texts')) {
|
|
object.texts.forEach((text) => {
|
|
canvas?.remove(text)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const commonMoveObject = (obj) => {
|
|
if (obj) {
|
|
obj.set({
|
|
lockMovementX: false,
|
|
lockMovementY: false,
|
|
})
|
|
|
|
const originLeft = obj.left
|
|
const originTop = obj.top
|
|
|
|
addCanvasMouseEventListener('mouse:up', (e) => {
|
|
obj.set({
|
|
lockMovementX: true,
|
|
lockMovementY: true,
|
|
})
|
|
initEvent()
|
|
obj.setCoords()
|
|
updateGroupObjectCoords(obj, originLeft, originTop)
|
|
canvas?.renderAll()
|
|
})
|
|
}
|
|
}
|
|
|
|
const commonCopyObject = (obj) => {
|
|
if (obj) {
|
|
//도머는 복사하기 보다 새로 호출해서 만드는 방법으로 함
|
|
if (obj.name == BATCH_TYPE.TRIANGLE_DORMER || obj.name == BATCH_TYPE.PENTAGON_DORMER) {
|
|
//그룹 객체 0번에 도머 속성을 넣어둠
|
|
const dormerAttributes = obj._objects[0].dormerAttributes
|
|
const dormerName = obj._objects[0].name
|
|
|
|
const dormerParams = {
|
|
height: dormerAttributes.height,
|
|
width: dormerAttributes.width,
|
|
pitch: dormerAttributes.pitch,
|
|
offsetRef: dormerAttributes.offsetRef,
|
|
offsetWidthRef: dormerAttributes.offsetWidthRef,
|
|
directionRef: dormerAttributes.directionRef,
|
|
}
|
|
|
|
const buttonAct = dormerName == BATCH_TYPE.TRIANGLE_DORMER ? 3 : 4
|
|
applyDormers(dormerParams, buttonAct)
|
|
} else {
|
|
let clonedObj = null
|
|
|
|
obj.clone((cloned) => {
|
|
clonedObj = cloned
|
|
clonedObj.fontSize = lengthTextFont.fontSize.value
|
|
})
|
|
|
|
addCanvasMouseEventListener('mouse:move', (e) => {
|
|
const pointer = canvas?.getPointer(e.e)
|
|
if (!clonedObj) return
|
|
|
|
canvas
|
|
.getObjects()
|
|
.filter((obj) => obj.name === 'clonedObj')
|
|
.forEach((obj) => canvas?.remove(obj))
|
|
|
|
clonedObj.set({
|
|
left: pointer.x,
|
|
top: pointer.y,
|
|
name: 'clonedObj',
|
|
})
|
|
canvas.add(clonedObj)
|
|
})
|
|
|
|
addCanvasMouseEventListener('mouse:down', (e) => {
|
|
clonedObj.set({
|
|
lockMovementX: true,
|
|
lockMovementY: true,
|
|
name: obj.name,
|
|
editable: false,
|
|
id: uuidv4(), //복사된 객체라 새로 따준다
|
|
})
|
|
|
|
//객체가 그룹일 경우에는 그룹 아이디를 따로 넣어준다
|
|
if (clonedObj.type === 'group') clonedObj.set({ groupId: uuidv4() })
|
|
|
|
//배치면일 경우
|
|
if (obj.name === 'roof') {
|
|
clonedObj.setCoords()
|
|
clonedObj.fire('modified')
|
|
clonedObj.fire('polygonMoved')
|
|
clonedObj.set({ direction: obj.direction, directionText: obj.directionText, roofMaterial: obj.roofMaterial })
|
|
|
|
obj.lines.forEach((line, index) => {
|
|
clonedObj.lines[index].set({ attributes: line.attributes })
|
|
})
|
|
|
|
canvas.renderAll()
|
|
addLengthText(clonedObj) //수치 추가
|
|
drawDirectionArrow(clonedObj) //방향 화살표 추가
|
|
}
|
|
|
|
initEvent()
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
const editText = () => {
|
|
const obj = canvas?.getActiveObject()
|
|
obj.set({ editable: true })
|
|
obj.enterEditing()
|
|
commonTextKeyEvent()
|
|
}
|
|
|
|
const deleteObject = () => {
|
|
const selectedObj = canvas?.getActiveObjects()
|
|
if (selectedObj) {
|
|
selectedObj.forEach((obj) => {
|
|
commonDeleteText(obj)
|
|
})
|
|
}
|
|
|
|
selectedObj.forEach((obj) => {
|
|
if (obj.type === 'group') {
|
|
obj._objects.forEach((lines) => {
|
|
if (lines.hasOwnProperty('arrow')) {
|
|
canvas
|
|
.getObjects()
|
|
.filter((obj1) => obj1.name === 'arrow' && lines.id === obj1.parentId)
|
|
.forEach((arrow) => {
|
|
canvas?.remove(arrow)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
const moveObject = () => {
|
|
const obj = canvas?.getActiveObject()
|
|
commonMoveObject(obj)
|
|
}
|
|
|
|
const copyObject = () => {
|
|
const obj = canvas?.getActiveObject()
|
|
commonCopyObject(obj)
|
|
}
|
|
|
|
const closeDistancePopup = () => {
|
|
const obj = canvas?.getObjects().filter((obj) => obj.name === 'distance')
|
|
if (obj) canvas.remove(...obj)
|
|
initEvent()
|
|
}
|
|
|
|
//선택된 그룹객체 restore 하고 item으로 다시 그리고 그 그린 객체 가지고 수정해서 재그룹화 시킨다
|
|
|
|
const changeDimensionExtendLine = () => {
|
|
const group = canvas?.getActiveObject()
|
|
const restoreGroup = group._restoreObjectsState()
|
|
canvas?.remove(group)
|
|
canvas?.renderAll()
|
|
|
|
restoreGroup._objects.forEach((obj) => {
|
|
canvas?.add(obj)
|
|
})
|
|
|
|
const id = group.groupId
|
|
const originLineDirection = group.lineDirection
|
|
const textObj = canvas?.getObjects().filter((obj) => obj.name === 'dimensionLineText' && obj.id === id)[0]
|
|
const centerLine = canvas?.getObjects().filter((obj) => obj.name === 'centerLine' && obj.id === id)[0]
|
|
const extendLine = canvas?.getObjects().filter((obj) => obj.name === 'extendLine' && obj.id === id)
|
|
const arrows = canvas?.getObjects().filter((obj) => obj.name === 'arrow' && obj.id === id)
|
|
|
|
const originX = centerLine.x1
|
|
const originY = centerLine.y1
|
|
let reGroupObj = []
|
|
|
|
addCanvasMouseEventListener('mouse:down', (e) => {
|
|
const pointer = canvas?.getPointer(e.e)
|
|
|
|
if (originLineDirection === 'horizontal') {
|
|
centerLine.set({
|
|
x1: centerLine.x1,
|
|
y1: pointer.y,
|
|
x2: centerLine.x2,
|
|
y2: pointer.y,
|
|
})
|
|
|
|
const differenceY = centerLine.y1 - originY
|
|
|
|
extendLine.forEach((obj) => {
|
|
obj.set({
|
|
x1: obj.x1,
|
|
y1: originY,
|
|
x2: obj.x2,
|
|
y2: differenceY > 0 ? pointer.y + 20 : pointer.y - 20,
|
|
})
|
|
})
|
|
|
|
arrows.forEach((arrow) => {
|
|
arrow.set({
|
|
top: pointer.y,
|
|
})
|
|
})
|
|
|
|
textObj.set({
|
|
top: pointer.y + 15,
|
|
})
|
|
textObj.setCoords()
|
|
} else {
|
|
centerLine.set({
|
|
x1: pointer.x,
|
|
y1: centerLine.y1,
|
|
x2: pointer.x,
|
|
y2: centerLine.y2,
|
|
})
|
|
|
|
const differenceX = centerLine.x1 - originX
|
|
|
|
extendLine.forEach((obj) => {
|
|
obj.set({
|
|
x1: originX,
|
|
y1: obj.y1,
|
|
x2: differenceX > 0 ? pointer.x + 20 : pointer.x - 20,
|
|
y2: obj.y2,
|
|
})
|
|
})
|
|
|
|
arrows.forEach((arrow) => {
|
|
arrow.set({
|
|
left: pointer.x,
|
|
})
|
|
})
|
|
|
|
textObj.set({
|
|
left: pointer.x - 15,
|
|
})
|
|
textObj.setCoords()
|
|
}
|
|
|
|
reGroupObj.push(centerLine, ...extendLine, ...arrows, textObj)
|
|
canvas?.remove(centerLine, ...extendLine, ...arrows, textObj)
|
|
|
|
const reGroup = new fabric.Group(reGroupObj, {
|
|
name: 'dimensionGroup',
|
|
selectable: true,
|
|
lineDirection: originLineDirection,
|
|
groupId: id,
|
|
})
|
|
|
|
reGroupObj = []
|
|
canvas.add(reGroup)
|
|
initEvent()
|
|
})
|
|
}
|
|
|
|
// 그룹 이동 시 라인 및 각 객체의 좌표를 절대 좌표로 업데이트하는 함수
|
|
function updateGroupObjectCoords(targetObj, originLeft, originTop) {
|
|
const diffrenceLeft = targetObj.left - originLeft
|
|
const diffrenceTop = targetObj.top - originTop
|
|
|
|
if (targetObj.type === 'group') {
|
|
targetObj.getObjects().forEach((obj) => {
|
|
// 그룹 내 객체의 절대 좌표를 계산
|
|
|
|
const originObjLeft = obj.left
|
|
const originObjTop = obj.top
|
|
|
|
if (obj.type === 'line') {
|
|
// Line 객체의 경우, x1, y1, x2, y2 절대 좌표 계산
|
|
|
|
obj.set({
|
|
x1: obj.x1 + diffrenceLeft,
|
|
y1: obj.y1 + diffrenceTop,
|
|
x2: obj.x2 + diffrenceLeft,
|
|
y2: obj.y2 + diffrenceTop,
|
|
})
|
|
|
|
obj.set({
|
|
left: originObjLeft,
|
|
top: originObjTop,
|
|
})
|
|
obj.fire('modified')
|
|
} else {
|
|
// 다른 객체의 경우 left, top 절대 좌표 설정
|
|
obj.set({
|
|
left: obj.left,
|
|
top: obj.top,
|
|
})
|
|
obj.fire('modified')
|
|
}
|
|
obj.setCoords() // 좌표 반영
|
|
})
|
|
} else {
|
|
if (targetObj.type === 'line') {
|
|
const originObjLeft = obj.left
|
|
const originObjTop = obj.top
|
|
|
|
if (obj.type === 'line') {
|
|
// Line 객체의 경우, x1, y1, x2, y2 절대 좌표 계산
|
|
|
|
obj.set({
|
|
x1: obj.x1 + diffrenceLeft,
|
|
y1: obj.y1 + diffrenceTop,
|
|
x2: obj.x2 + diffrenceLeft,
|
|
y2: obj.y2 + diffrenceTop,
|
|
})
|
|
|
|
obj.set({
|
|
left: originObjLeft,
|
|
top: originObjTop,
|
|
})
|
|
obj.fire('modified')
|
|
} else {
|
|
targetObj.set({
|
|
...targetObj,
|
|
left: targetObj.left,
|
|
top: targetObj.top,
|
|
})
|
|
obj.fire('modified')
|
|
}
|
|
targetObj.setCoords()
|
|
}
|
|
canvas?.renderAll()
|
|
}
|
|
}
|
|
|
|
const deleteOuterLineObject = () => {
|
|
const selectedOuterLine = canvas.getActiveObject()
|
|
if (selectedOuterLine && selectedOuterLine.name === 'outerLine') {
|
|
canvas.remove(selectedOuterLine)
|
|
canvas.renderAll()
|
|
}
|
|
}
|
|
|
|
return {
|
|
commonFunctions,
|
|
dimensionSettings,
|
|
commonMoveObject,
|
|
commonDeleteText,
|
|
deleteObject,
|
|
moveObject,
|
|
copyObject,
|
|
editText,
|
|
changeDimensionExtendLine,
|
|
deleteOuterLineObject,
|
|
}
|
|
}
|