useCommon.js 생성 후 잡 기능 이관
This commit is contained in:
parent
bbd0e365be
commit
1df9facaea
@ -18,8 +18,6 @@ import { appMessageStore, globalLocaleStore } from '@/store/localeAtom'
|
|||||||
import { settingModalFirstOptionsState, wordDisplaySelector } from '@/store/settingAtom'
|
import { settingModalFirstOptionsState, wordDisplaySelector } from '@/store/settingAtom'
|
||||||
import { MENU } from '@/common/common'
|
import { MENU } from '@/common/common'
|
||||||
|
|
||||||
import { checkLineOrientation, getDistance } from '@/util/canvas-util'
|
|
||||||
|
|
||||||
import KO from '@/locales/ko.json'
|
import KO from '@/locales/ko.json'
|
||||||
import JA from '@/locales/ja.json'
|
import JA from '@/locales/ja.json'
|
||||||
import { useCanvasEvent } from '@/hooks/useCanvasEvent'
|
import { useCanvasEvent } from '@/hooks/useCanvasEvent'
|
||||||
@ -28,6 +26,7 @@ import SettingModal01 from '@/components/floor-plan/modal/setting01/SettingModal
|
|||||||
import { usePopup } from '@/hooks/usePopup'
|
import { usePopup } from '@/hooks/usePopup'
|
||||||
import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom'
|
import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom'
|
||||||
import PlacementShapeSetting from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting'
|
import PlacementShapeSetting from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting'
|
||||||
|
import { useCommonUtils } from '@/hooks/common/useCommonUtils'
|
||||||
|
|
||||||
const canvasMenus = [
|
const canvasMenus = [
|
||||||
{ index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING },
|
{ index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING },
|
||||||
@ -57,12 +56,11 @@ export default function CanvasMenu(props) {
|
|||||||
const globalLocale = useRecoilValue(globalLocaleStore)
|
const globalLocale = useRecoilValue(globalLocaleStore)
|
||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
const sessionState = useRecoilValue(sessionStore)
|
const sessionState = useRecoilValue(sessionStore)
|
||||||
const wordDisplay = useRecoilValue(wordDisplaySelector)
|
|
||||||
|
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
const { saveCanvas } = usePlan()
|
const { saveCanvas } = usePlan()
|
||||||
const { swalFire } = useSwal()
|
const { swalFire } = useSwal()
|
||||||
const { addCanvasMouseEventListener, initEvent, addDocumentEventListener } = useEvent()
|
const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useEvent()
|
||||||
|
|
||||||
const [commonFunctionState, setCommonFunctionState] = useState({
|
const [commonFunctionState, setCommonFunctionState] = useState({
|
||||||
text: false,
|
text: false,
|
||||||
@ -70,6 +68,12 @@ export default function CanvasMenu(props) {
|
|||||||
distance: false,
|
distance: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { commonFunctions } = useCommonUtils({
|
||||||
|
canvas,
|
||||||
|
commonFunctionState,
|
||||||
|
setCommonFunctionState,
|
||||||
|
})
|
||||||
|
|
||||||
const [popup, setPopup] = useRecoilState(popupState)
|
const [popup, setPopup] = useRecoilState(popupState)
|
||||||
|
|
||||||
const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }]
|
const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }]
|
||||||
@ -148,335 +152,6 @@ export default function CanvasMenu(props) {
|
|||||||
addPopup(id, 0, <SettingModal01 id={id} />)
|
addPopup(id, 0, <SettingModal01 id={id} />)
|
||||||
}
|
}
|
||||||
|
|
||||||
const commonTextMode = () => {
|
|
||||||
let textbox
|
|
||||||
if (commonFunctionState.text) {
|
|
||||||
addCanvasMouseEventListener('mouse:down', (event) => {
|
|
||||||
const pointer = canvas?.getPointer(event.e)
|
|
||||||
textbox = new fabric.Textbox('', {
|
|
||||||
left: pointer.x,
|
|
||||||
top: pointer.y,
|
|
||||||
width: 200,
|
|
||||||
fontSize: 14,
|
|
||||||
editable: true,
|
|
||||||
name: 'commonText',
|
|
||||||
visible: wordDisplay,
|
|
||||||
})
|
|
||||||
|
|
||||||
canvas?.add(textbox)
|
|
||||||
canvas.setActiveObject(textbox)
|
|
||||||
textbox.enterEditing()
|
|
||||||
textbox.selectAll()
|
|
||||||
})
|
|
||||||
|
|
||||||
addDocumentEventListener('keydown', document, (e) => {
|
|
||||||
if (e.key === 'Enter') {
|
|
||||||
if (commonFunctionState.text) {
|
|
||||||
const activeObject = canvas.getActiveObject()
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const commonDimensionMode = () => {
|
|
||||||
if (commonFunctionState.dimension) {
|
|
||||||
let points = []
|
|
||||||
let distanceText = null
|
|
||||||
let minX, minY, maxX, maxY
|
|
||||||
|
|
||||||
// 화살표를 생성하는 함수
|
|
||||||
function createArrow(x, y, angle) {
|
|
||||||
return new fabric.Triangle({
|
|
||||||
left: x,
|
|
||||||
top: y,
|
|
||||||
originX: 'center',
|
|
||||||
originY: 'center',
|
|
||||||
angle: angle,
|
|
||||||
width: 15,
|
|
||||||
height: 15,
|
|
||||||
fill: 'black',
|
|
||||||
selectable: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const circleOptions = {
|
|
||||||
radius: 5,
|
|
||||||
strokeWidth: 2,
|
|
||||||
stroke: 'red',
|
|
||||||
fill: 'white',
|
|
||||||
selectable: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
const lineOptions = {
|
|
||||||
stroke: 'black',
|
|
||||||
strokeWidth: 2,
|
|
||||||
selectable: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 캔버스에 클릭 이벤트 추가
|
|
||||||
addCanvasMouseEventListener('mouse:down', (e) => {
|
|
||||||
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)
|
|
||||||
canvas.add(line)
|
|
||||||
|
|
||||||
const distance = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY)
|
|
||||||
const lineDirection = checkLineOrientation(line)
|
|
||||||
let extendLine = []
|
|
||||||
|
|
||||||
if (lineDirection === 'horizontal') {
|
|
||||||
extendLine = [
|
|
||||||
[line.x1, line.y1 - 20, line.x1, line.y1 + 20],
|
|
||||||
[line.x2, line.y2 - 20, line.x2, line.y2 + 20],
|
|
||||||
]
|
|
||||||
} else {
|
|
||||||
extendLine = [
|
|
||||||
[line.x1 - 20, line.y1, line.x1 + 20, line.y1],
|
|
||||||
[line.x2 - 20, line.y2, line.x2 + 20, line.y2],
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
extendLine.forEach((line) => {
|
|
||||||
const extendLine = new fabric.Line(line, lineOptions)
|
|
||||||
canvas.add(extendLine)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 두 포인트 간의 각도를 계산하여 화살표 추가
|
|
||||||
// const angle = calculateAngle({ x: p1CenterX, y: p1CenterY }, { x: p2CenterX, y: p2CenterY })
|
|
||||||
|
|
||||||
// 첫 번째 포인트에 화살표 추가
|
|
||||||
|
|
||||||
const paddingX = lineDirection === 'horizontal' ? p1CenterX + 7.5 : p1CenterX + 1
|
|
||||||
const paddingX2 = lineDirection === 'horizontal' ? p2CenterX - 6.5 : p2CenterX + 1
|
|
||||||
const paddingY = lineDirection === 'horizontal' ? p1CenterY + 1 : p1CenterY + 8
|
|
||||||
const paddingY2 = lineDirection === 'horizontal' ? p2CenterY + 1 : p2CenterY - 8
|
|
||||||
|
|
||||||
const arrow1 = createArrow(paddingX, paddingY, lineDirection === 'horizontal' ? -90 : 0) // 반대 방향 화살표
|
|
||||||
const arrow2 = createArrow(paddingX2, paddingY2, lineDirection === 'horizontal' ? 90 : 180) // 정방향 화살표
|
|
||||||
canvas.add(arrow1)
|
|
||||||
canvas.add(arrow2)
|
|
||||||
|
|
||||||
// 두 포인트 간의 거리 계산
|
|
||||||
|
|
||||||
// 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성
|
|
||||||
distanceText = new fabric.Text(`${distance * 10}`, {
|
|
||||||
left: (p1CenterX + p2CenterX) / 2 + (lineDirection === 'horizontal' ? 0 : -15),
|
|
||||||
top: (p1CenterY + p2CenterY) / 2 + (lineDirection === 'horizontal' ? +15 : 0),
|
|
||||||
fill: 'black',
|
|
||||||
fontSize: 16,
|
|
||||||
selectable: true,
|
|
||||||
textAlign: 'center',
|
|
||||||
originX: 'center',
|
|
||||||
originY: 'center',
|
|
||||||
angle: lineDirection === 'horizontal' ? 0 : 270,
|
|
||||||
name: 'lengthText',
|
|
||||||
// lockMovementX: false,
|
|
||||||
// lockMovementY: false,
|
|
||||||
})
|
|
||||||
canvas.add(distanceText)
|
|
||||||
|
|
||||||
// minX = p1CenterX
|
|
||||||
// maxX = p2CenterX
|
|
||||||
// minY = p1CenterY
|
|
||||||
// maxY = p2CenterY
|
|
||||||
|
|
||||||
// 거리 계산 후, 다음 측정을 위해 초기화
|
|
||||||
points = []
|
|
||||||
}
|
|
||||||
|
|
||||||
// 캔버스 다시 그리기
|
|
||||||
canvas.renderAll()
|
|
||||||
})
|
|
||||||
|
|
||||||
// addCanvasMouseEventListener('object:moving', function (e) {
|
|
||||||
// const obj = e.target
|
|
||||||
|
|
||||||
// if (obj.left < minX) {
|
|
||||||
// obj.left = minX
|
|
||||||
// }
|
|
||||||
// if (obj.left + obj.width > maxX) {
|
|
||||||
// obj.left = maxX - obj.width
|
|
||||||
// }
|
|
||||||
// if (obj.top < minY) {
|
|
||||||
// obj.top = minY
|
|
||||||
// }
|
|
||||||
// if (obj.top + obj.height > maxY) {
|
|
||||||
// obj.top = maxY - obj.height
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const commonDistanceMode = () => {
|
|
||||||
if (commonFunctionState.distance) {
|
|
||||||
let points = []
|
|
||||||
let distanceText = null
|
|
||||||
|
|
||||||
const circleOptions = {
|
|
||||||
radius: 5,
|
|
||||||
strokeWidth: 2,
|
|
||||||
stroke: 'red',
|
|
||||||
fill: 'white',
|
|
||||||
selectable: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
const lineOptions = {
|
|
||||||
stroke: 'black',
|
|
||||||
strokeWidth: 2,
|
|
||||||
selectable: false,
|
|
||||||
strokeDashArray: [9, 5],
|
|
||||||
}
|
|
||||||
|
|
||||||
const textOptions = {
|
|
||||||
fill: 'black',
|
|
||||||
fontSize: 16,
|
|
||||||
selectable: true,
|
|
||||||
textAlign: 'center',
|
|
||||||
originX: 'center',
|
|
||||||
originY: 'center',
|
|
||||||
}
|
|
||||||
|
|
||||||
// 캔버스에 클릭 이벤트 추가
|
|
||||||
addCanvasMouseEventListener('mouse:down', function (options) {
|
|
||||||
const pointer = canvas.getPointer(options.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]
|
|
||||||
|
|
||||||
point = new fabric.Circle({
|
|
||||||
left: pointer.x - 5, // 반지름 반영
|
|
||||||
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
|
|
||||||
|
|
||||||
const p3 = new fabric.Point(p2CenterX, p1CenterY)
|
|
||||||
|
|
||||||
// 두 포인트 간에 직선을 그림 (중심을 기준으로)
|
|
||||||
const line = new fabric.Line([p1CenterX, p1CenterY, p2CenterX, p2CenterY], lineOptions)
|
|
||||||
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(line)
|
|
||||||
canvas.add(line2)
|
|
||||||
canvas.add(line3)
|
|
||||||
|
|
||||||
const distance1 = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY)
|
|
||||||
const distance2 = getDistance(p2CenterX, p2CenterY, p3.x, p3.y)
|
|
||||||
const distance3 = getDistance(p3.x, p3.y, p1CenterX, p1CenterY)
|
|
||||||
|
|
||||||
// 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성
|
|
||||||
distanceText = new fabric.Text(`${distance1}`, {
|
|
||||||
left: (p1CenterX + p2CenterX) / 2,
|
|
||||||
top: (p1CenterY + p2CenterY) / 2,
|
|
||||||
...textOptions,
|
|
||||||
})
|
|
||||||
canvas.add(distanceText)
|
|
||||||
distanceText = new fabric.Text(`${distance2}`, {
|
|
||||||
left: (p2CenterX + p3.x) / 2,
|
|
||||||
top: (p2CenterY + p3.y) / 2,
|
|
||||||
...textOptions,
|
|
||||||
})
|
|
||||||
canvas.add(distanceText)
|
|
||||||
distanceText = new fabric.Text(`${distance3}`, {
|
|
||||||
left: (p3.x + p1CenterX) / 2,
|
|
||||||
top: (p3.y + p1CenterY) / 2,
|
|
||||||
...textOptions,
|
|
||||||
})
|
|
||||||
canvas.add(distanceText)
|
|
||||||
|
|
||||||
// 거리 계산 후, 다음 측정을 위해 초기화
|
|
||||||
points = []
|
|
||||||
}
|
|
||||||
|
|
||||||
// 캔버스 다시 그리기
|
|
||||||
canvas.renderAll()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (globalLocale === 'ko') {
|
if (globalLocale === 'ko') {
|
||||||
setAppMessageState(KO)
|
setAppMessageState(KO)
|
||||||
@ -485,35 +160,6 @@ export default function CanvasMenu(props) {
|
|||||||
}
|
}
|
||||||
}, [menuNumber, type, globalLocale])
|
}, [menuNumber, type, globalLocale])
|
||||||
|
|
||||||
const commonFunctions = (mode) => {
|
|
||||||
let tempStates = { ...commonFunctionState }
|
|
||||||
|
|
||||||
if (tempStates[mode]) {
|
|
||||||
tempStates[mode] = false
|
|
||||||
} else {
|
|
||||||
Object.keys(tempStates).forEach((key) => {
|
|
||||||
tempStates[key] = false
|
|
||||||
})
|
|
||||||
|
|
||||||
if (mode !== undefined) {
|
|
||||||
tempStates[mode] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setCommonFunctionState(tempStates)
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
initEvent()
|
|
||||||
if (commonFunctionState.text) {
|
|
||||||
commonTextMode()
|
|
||||||
} else if (commonFunctionState.dimension) {
|
|
||||||
commonDimensionMode()
|
|
||||||
} else if (commonFunctionState.distance) {
|
|
||||||
commonDistanceMode()
|
|
||||||
}
|
|
||||||
}, [commonFunctionState])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`canvas-menu-wrap ${menuNumber === 2 || menuNumber === 3 || menuNumber === 4 ? 'active' : ''}`}>
|
<div className={`canvas-menu-wrap ${menuNumber === 2 || menuNumber === 3 || menuNumber === 4 ? 'active' : ''}`}>
|
||||||
<div className="canvas-menu-inner">
|
<div className="canvas-menu-inner">
|
||||||
|
|||||||
@ -0,0 +1,367 @@
|
|||||||
|
import { useEffect } from 'react'
|
||||||
|
import { useRecoilValue } from 'recoil'
|
||||||
|
import { wordDisplaySelector } from '@/store/settingAtom'
|
||||||
|
import { checkLineOrientation, getDistance } from '@/util/canvas-util'
|
||||||
|
import { useEvent } from '@/hooks/useEvent'
|
||||||
|
|
||||||
|
export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionState }) {
|
||||||
|
const wordDisplay = useRecoilValue(wordDisplaySelector)
|
||||||
|
const { addCanvasMouseEventListener, addDocumentEventListener, initEvent } = useEvent()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
initEvent()
|
||||||
|
if (commonFunctionState.text) {
|
||||||
|
commonTextMode()
|
||||||
|
} else if (commonFunctionState.dimension) {
|
||||||
|
commonDimensionMode()
|
||||||
|
} else if (commonFunctionState.distance) {
|
||||||
|
commonDistanceMode()
|
||||||
|
}
|
||||||
|
}, [commonFunctionState])
|
||||||
|
|
||||||
|
const commonTextMode = () => {
|
||||||
|
let textbox
|
||||||
|
if (commonFunctionState.text) {
|
||||||
|
addCanvasMouseEventListener('mouse:down', (event) => {
|
||||||
|
const pointer = canvas?.getPointer(event.e)
|
||||||
|
textbox = new fabric.Textbox('', {
|
||||||
|
left: pointer.x,
|
||||||
|
top: pointer.y,
|
||||||
|
width: 200,
|
||||||
|
fontSize: 14,
|
||||||
|
editable: true,
|
||||||
|
name: 'commonText',
|
||||||
|
visible: wordDisplay,
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas?.add(textbox)
|
||||||
|
canvas.setActiveObject(textbox)
|
||||||
|
textbox.enterEditing()
|
||||||
|
textbox.selectAll()
|
||||||
|
})
|
||||||
|
|
||||||
|
addDocumentEventListener('keydown', document, (e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
if (commonFunctionState.text) {
|
||||||
|
const activeObject = canvas.getActiveObject()
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const commonDimensionMode = () => {
|
||||||
|
if (commonFunctionState.dimension) {
|
||||||
|
let points = []
|
||||||
|
let distanceText = null
|
||||||
|
let minX, minY, maxX, maxY
|
||||||
|
|
||||||
|
// 화살표를 생성하는 함수
|
||||||
|
function createArrow(x, y, angle) {
|
||||||
|
return new fabric.Triangle({
|
||||||
|
left: x,
|
||||||
|
top: y,
|
||||||
|
originX: 'center',
|
||||||
|
originY: 'center',
|
||||||
|
angle: angle,
|
||||||
|
width: 15,
|
||||||
|
height: 15,
|
||||||
|
fill: 'black',
|
||||||
|
selectable: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const circleOptions = {
|
||||||
|
radius: 5,
|
||||||
|
strokeWidth: 2,
|
||||||
|
stroke: 'red',
|
||||||
|
fill: 'white',
|
||||||
|
selectable: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
const lineOptions = {
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 2,
|
||||||
|
selectable: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 캔버스에 클릭 이벤트 추가
|
||||||
|
addCanvasMouseEventListener('mouse:down', (e) => {
|
||||||
|
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)
|
||||||
|
canvas.add(line)
|
||||||
|
|
||||||
|
const distance = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY)
|
||||||
|
const lineDirection = checkLineOrientation(line)
|
||||||
|
let extendLine = []
|
||||||
|
|
||||||
|
if (lineDirection === 'horizontal') {
|
||||||
|
extendLine = [
|
||||||
|
[line.x1, line.y1 - 20, line.x1, line.y1 + 20],
|
||||||
|
[line.x2, line.y2 - 20, line.x2, line.y2 + 20],
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
extendLine = [
|
||||||
|
[line.x1 - 20, line.y1, line.x1 + 20, line.y1],
|
||||||
|
[line.x2 - 20, line.y2, line.x2 + 20, line.y2],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
extendLine.forEach((line) => {
|
||||||
|
const extendLine = new fabric.Line(line, lineOptions)
|
||||||
|
canvas.add(extendLine)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 첫 번째 포인트에 화살표 추가
|
||||||
|
const paddingX = lineDirection === 'horizontal' ? p1CenterX + 7.5 : p1CenterX + 1
|
||||||
|
const paddingX2 = lineDirection === 'horizontal' ? p2CenterX - 6.5 : p2CenterX + 1
|
||||||
|
const paddingY = lineDirection === 'horizontal' ? p1CenterY + 1 : p1CenterY + 8
|
||||||
|
const paddingY2 = lineDirection === 'horizontal' ? p2CenterY + 1 : p2CenterY - 8
|
||||||
|
|
||||||
|
const arrow1 = createArrow(paddingX, paddingY, lineDirection === 'horizontal' ? -90 : 0) // 반대 방향 화살표
|
||||||
|
const arrow2 = createArrow(paddingX2, paddingY2, lineDirection === 'horizontal' ? 90 : 180) // 정방향 화살표
|
||||||
|
canvas.add(arrow1)
|
||||||
|
canvas.add(arrow2)
|
||||||
|
|
||||||
|
// 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성
|
||||||
|
distanceText = new fabric.Text(`${distance}`, {
|
||||||
|
left: (p1CenterX + p2CenterX) / 2 + (lineDirection === 'horizontal' ? 0 : -15),
|
||||||
|
top: (p1CenterY + p2CenterY) / 2 + (lineDirection === 'horizontal' ? +15 : 0),
|
||||||
|
fill: 'black',
|
||||||
|
fontSize: 16,
|
||||||
|
selectable: true,
|
||||||
|
textAlign: 'center',
|
||||||
|
originX: 'center',
|
||||||
|
originY: 'center',
|
||||||
|
angle: lineDirection === 'horizontal' ? 0 : 270,
|
||||||
|
// lockMovementX: false,
|
||||||
|
// lockMovementY: false,
|
||||||
|
})
|
||||||
|
canvas.add(distanceText)
|
||||||
|
|
||||||
|
// minX = p1CenterX
|
||||||
|
// maxX = p2CenterX
|
||||||
|
// minY = p1CenterY
|
||||||
|
// maxY = p2CenterY
|
||||||
|
|
||||||
|
// 거리 계산 후, 다음 측정을 위해 초기화
|
||||||
|
points = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 캔버스 다시 그리기
|
||||||
|
canvas.renderAll()
|
||||||
|
})
|
||||||
|
|
||||||
|
// addCanvasMouseEventListener('object:moving', function (e) {
|
||||||
|
// const obj = e.target
|
||||||
|
|
||||||
|
// if (obj.left < minX) {
|
||||||
|
// obj.left = minX
|
||||||
|
// }
|
||||||
|
// if (obj.left + obj.width > maxX) {
|
||||||
|
// obj.left = maxX - obj.width
|
||||||
|
// }
|
||||||
|
// if (obj.top < minY) {
|
||||||
|
// obj.top = minY
|
||||||
|
// }
|
||||||
|
// if (obj.top + obj.height > maxY) {
|
||||||
|
// obj.top = maxY - obj.height
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const commonDistanceMode = () => {
|
||||||
|
if (commonFunctionState.distance) {
|
||||||
|
let points = []
|
||||||
|
let distanceText = null
|
||||||
|
|
||||||
|
const circleOptions = {
|
||||||
|
radius: 5,
|
||||||
|
strokeWidth: 2,
|
||||||
|
stroke: 'red',
|
||||||
|
fill: 'white',
|
||||||
|
selectable: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
const lineOptions = {
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 2,
|
||||||
|
selectable: false,
|
||||||
|
strokeDashArray: [9, 5],
|
||||||
|
}
|
||||||
|
|
||||||
|
const textOptions = {
|
||||||
|
fill: 'black',
|
||||||
|
fontSize: 16,
|
||||||
|
selectable: true,
|
||||||
|
textAlign: 'center',
|
||||||
|
originX: 'center',
|
||||||
|
originY: 'center',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 캔버스에 클릭 이벤트 추가
|
||||||
|
addCanvasMouseEventListener('mouse:down', function (options) {
|
||||||
|
const pointer = canvas.getPointer(options.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]
|
||||||
|
|
||||||
|
point = new fabric.Circle({
|
||||||
|
left: pointer.x - 5, // 반지름 반영
|
||||||
|
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
|
||||||
|
|
||||||
|
const p3 = new fabric.Point(p2CenterX, p1CenterY)
|
||||||
|
|
||||||
|
// 두 포인트 간에 직선을 그림 (중심을 기준으로)
|
||||||
|
const line = new fabric.Line([p1CenterX, p1CenterY, p2CenterX, p2CenterY], lineOptions)
|
||||||
|
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(line)
|
||||||
|
canvas.add(line2)
|
||||||
|
canvas.add(line3)
|
||||||
|
|
||||||
|
const distance1 = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY)
|
||||||
|
const distance2 = getDistance(p2CenterX, p2CenterY, p3.x, p3.y)
|
||||||
|
const distance3 = getDistance(p3.x, p3.y, p1CenterX, p1CenterY)
|
||||||
|
|
||||||
|
// 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성
|
||||||
|
distanceText = new fabric.Text(`${distance1}`, {
|
||||||
|
left: (p1CenterX + p2CenterX) / 2,
|
||||||
|
top: (p1CenterY + p2CenterY) / 2,
|
||||||
|
...textOptions,
|
||||||
|
})
|
||||||
|
canvas.add(distanceText)
|
||||||
|
distanceText = new fabric.Text(`${distance2}`, {
|
||||||
|
left: (p2CenterX + p3.x) / 2,
|
||||||
|
top: (p2CenterY + p3.y) / 2,
|
||||||
|
...textOptions,
|
||||||
|
})
|
||||||
|
canvas.add(distanceText)
|
||||||
|
distanceText = new fabric.Text(`${distance3}`, {
|
||||||
|
left: (p3.x + p1CenterX) / 2,
|
||||||
|
top: (p3.y + p1CenterY) / 2,
|
||||||
|
...textOptions,
|
||||||
|
})
|
||||||
|
canvas.add(distanceText)
|
||||||
|
|
||||||
|
// 거리 계산 후, 다음 측정을 위해 초기화
|
||||||
|
points = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 캔버스 다시 그리기
|
||||||
|
canvas.renderAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const commonFunctions = (mode) => {
|
||||||
|
let tempStates = { ...commonFunctionState }
|
||||||
|
|
||||||
|
if (tempStates[mode]) {
|
||||||
|
tempStates[mode] = false
|
||||||
|
} else {
|
||||||
|
Object.keys(tempStates).forEach((key) => {
|
||||||
|
tempStates[key] = false
|
||||||
|
})
|
||||||
|
|
||||||
|
if (mode !== undefined) {
|
||||||
|
tempStates[mode] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setCommonFunctionState(tempStates)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
commonTextMode,
|
||||||
|
commonDimensionMode,
|
||||||
|
commonDistanceMode,
|
||||||
|
commonFunctions,
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user