diff --git a/src/components/floor-plan/CanvasFrame.jsx b/src/components/floor-plan/CanvasFrame.jsx index e6261edc..2f946deb 100644 --- a/src/components/floor-plan/CanvasFrame.jsx +++ b/src/components/floor-plan/CanvasFrame.jsx @@ -11,11 +11,16 @@ import { currentObjectState } from '@/store/canvasAtom' import { useCanvasEvent } from '@/hooks/useCanvasEvent' import QContextMenu from '@/components/common/context-menu/QContextMenu' import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize' +import { useCommonUtils } from '@/hooks/common/useCommonUtils' +import { useObjectBatch } from '@/hooks/object/useObjectBatch' +import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch' export default function CanvasFrame({ plan }) { const canvasRef = useRef(null) const { canvas } = useCanvas('canvas') const { handleZoomClear } = useCanvasEvent() + const { testAlert } = useCommonUtils({}) + const { contextMenu, currentContextMenu, setCurrentContextMenu, handleClick } = useContextMenu({ externalFn: { handleZoomClear, diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 07411efb..4017342d 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -27,6 +27,7 @@ import { usePopup } from '@/hooks/usePopup' import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom' import PlacementShapeSetting from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' import { useCommonUtils } from '@/hooks/common/useCommonUtils' +import { commonUtilsState } from '@/store/commonUtilsAtom' const canvasMenus = [ { index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING }, @@ -61,17 +62,8 @@ export default function CanvasMenu(props) { const { saveCanvas } = usePlan() const { swalFire } = useSwal() const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useEvent() - - const [commonFunctionState, setCommonFunctionState] = useState({ - text: false, - dimension: false, - distance: false, - }) - - const { commonFunctions } = useCommonUtils({ - commonFunctionState, - setCommonFunctionState, - }) + const commonUtils = useRecoilValue(commonUtilsState) + const { commonFunctions } = useCommonUtils() const [popup, setPopup] = useRecoilState(popupState) @@ -188,9 +180,9 @@ export default function CanvasMenu(props) { }
- - - + + +
diff --git a/src/components/floor-plan/modal/distance/Distance.jsx b/src/components/floor-plan/modal/distance/Distance.jsx index 06a7a483..70ddfb35 100644 --- a/src/components/floor-plan/modal/distance/Distance.jsx +++ b/src/components/floor-plan/modal/distance/Distance.jsx @@ -1,15 +1,20 @@ -import WithDraggable from '@/components/common/draggable/withDraggable' +import { useRecoilValue } from 'recoil' import { useMessage } from '@/hooks/useMessage' import { usePopup } from '@/hooks/usePopup' -import { useRecoilValue } from 'recoil' +import WithDraggable from '@/components/common/draggable/WithDraggable' import { contextPopupPositionState } from '@/store/popupAtom' export default function Distance(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) - const { id, pos = contextPopupPosition, distance } = props + const { id, pos = contextPopupPosition, distance, deleteDistance } = props const { getMessage } = useMessage() const { closePopup } = usePopup() + const handleClose = () => { + deleteDistance() + closePopup(id) + } + return (
@@ -58,7 +63,9 @@ export default function Distance(props) {
- +
diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js index 70447ae8..5f02900d 100644 --- a/src/hooks/common/useCommonUtils.js +++ b/src/hooks/common/useCommonUtils.js @@ -1,5 +1,5 @@ import { useEffect } from 'react' -import { useRecoilValue } from 'recoil' +import { useRecoilValue, useRecoilState } from 'recoil' import { wordDisplaySelector } from '@/store/settingAtom' import { useEvent } from '@/hooks/useEvent' import { checkLineOrientation, getDistance } from '@/util/canvas-util' @@ -9,30 +9,34 @@ import { canvasState } from '@/store/canvasAtom' import { v4 as uuidv4 } from 'uuid' import { usePopup } from '@/hooks/usePopup' import Distance from '@/components/floor-plan/modal/distance/Distance' +import { commonUtilsState } from '@/store/commonUtilsAtom' +import { point } from '@turf/turf' -export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) { +export function useCommonUtils() { const canvas = useRecoilValue(canvasState) const wordDisplay = useRecoilValue(wordDisplaySelector) const { addCanvasMouseEventListener, addDocumentEventListener, initEvent } = useEvent() const dimensionSettings = useRecoilValue(dimensionLineSettingsState) const dimensionLineTextFont = useRecoilValue(fontSelector('dimensionLineText')) const commonTextFont = useRecoilValue(fontSelector('commonText')) + const [commonUtils, setCommonUtilsState] = useRecoilState(commonUtilsState) + const { addPopup } = usePopup() useEffect(() => { initEvent() - if (commonFunctionState.text) { + if (commonUtils.text) { commonTextMode() - } else if (commonFunctionState.dimension) { + } else if (commonUtils.dimension) { commonDimensionMode() - } else if (commonFunctionState.distance) { + } else if (commonUtils.distance) { commonDistanceMode() } - }, [commonFunctionState, dimensionSettings, commonTextFont, dimensionLineTextFont]) + }, [commonUtils, dimensionSettings, commonTextFont, dimensionLineTextFont]) const commonTextMode = () => { let textbox - if (commonFunctionState.text) { + if (commonUtils.text) { addCanvasMouseEventListener('mouse:down', (event) => { const pointer = canvas?.getPointer(event.e) textbox = new fabric.Textbox('', { @@ -46,6 +50,11 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) fontFamily: commonTextFont.fontFamily.value, fontSize: commonTextFont.fontSize.value, fontStyle: commonTextFont.fontWeight.value, + selectable: true, + lockMovementX: true, + lockMovementY: true, + originX: 'center', + originY: 'center', }) canvas?.add(textbox) @@ -53,70 +62,120 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) 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 }) - }) + 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, + }) + } - canvas.renderAll() - } - } - } - }) + 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 (commonFunctionState.dimension) { + if (commonUtils.dimension) { + const uuid = uuidv4() + 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: dimensionSettings.color, - selectable: false, - }) - } const circleOptions = { radius: 5, strokeWidth: 2, stroke: 'red', fill: 'white', - selectable: false, + selectable: true, } const lineOptions = { stroke: dimensionSettings.color, strokeWidth: dimensionSettings.pixel, - name: 'dimensionLine', selectable: true, + originX: 'center', + originY: 'center', } // 캔버스에 클릭 이벤트 추가 addCanvasMouseEventListener('mouse:down', (e) => { + let groupObjects = [] + const pointer = canvas.getPointer(e.e) + let point if (points.length === 0) { @@ -165,40 +224,60 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) }) // 두 포인트 간에 직선을 그림 (중심을 기준으로) - const line = new fabric.Line([p1CenterX, p1CenterY, p2CenterX, p2CenterY], lineOptions) + 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) - 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], - ] - } + const extendListArray = createDimensionExtendLine(line, lineDirection) - extendLine.forEach((line) => { - const extendLine = new fabric.Line(line, lineOptions) - canvas.add(extendLine) + extendListArray.forEach((line) => { + const extendLine = new fabric.Line(line, { ...lineOptions, name: 'extendLine', id: uuid }) + // canvas.add(extendLine) + groupObjects.push(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 + // // 첫 번째 포인트에 화살표 추가 좌측 -> 우측으로 그릴때 + // 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 - const arrow1 = createArrow(paddingX, paddingY, lineDirection === 'horizontal' ? -90 : 0) // 반대 방향 화살표 - const arrow2 = createArrow(paddingX2, paddingY2, lineDirection === 'horizontal' ? 90 : 180) // 정방향 화살표 - canvas.add(arrow1) - canvas.add(arrow2) + // // 우측 -> 좌측으로 그릴땐 반대 + // 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 + // } + + 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) // 정방향 화살표 + // canvas.add(arrow1) + // canvas.add(arrow2) + + groupObjects.push(arrow1) + groupObjects.push(arrow2) + + const group = new fabric.Group(groupObjects, { + name: 'dimensionLine', + selectable: true, + originX: 'center', + originY: 'center', + lineDirection: lineDirection, + id: uuid, + }) + + canvas.add(group) distanceText = new fabric.Text(`${distance * 10} `, { left: (p1CenterX + p2CenterX) / 2 + (lineDirection === 'horizontal' ? 0 : -15), @@ -213,18 +292,24 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) originY: 'center', angle: lineDirection === 'horizontal' ? 0 : 270, name: 'dimensionLineText', + id: uuid, // lockMovementX: false, // lockMovementY: false, }) canvas.add(distanceText) - // minX = p1CenterX - // maxX = p2CenterX - // minY = p1CenterY - // maxY = p2CenterY + // groupObjects.push(distanceText) + + canvas.renderAll() // 거리 계산 후, 다음 측정을 위해 초기화 points = [] + + if (setCommonUtilsState) + setCommonUtilsState({ + ...commonUtilsState, + dimension: false, + }) } // 캔버스 다시 그리기 @@ -251,7 +336,7 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) } const commonDistanceMode = () => { - if (commonFunctionState.distance) { + if (commonUtils.distance) { let points = [] let distanceText = null let drawPoints = [] @@ -261,13 +346,15 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) strokeWidth: 1, originX: 'center', originY: 'center', + name: 'distance', } const lineOptions = { stroke: 'black', - strokeWidth: 2, + strokeWidth: 1, selectable: false, - strokeDashArray: [9, 5], + strokeDashArray: [10, 5], + name: 'distance', } const textOptions = { @@ -277,11 +364,12 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) textAlign: 'center', originX: 'center', originY: 'center', + name: 'distance', } // 캔버스에 클릭 이벤트 추가 - addCanvasMouseEventListener('mouse:down', function (options) { - const pointer = canvas.getPointer(options.e) + addCanvasMouseEventListener('mouse:down', function (e) { + const pointer = canvas.getPointer(e.e) let point let cross = {} @@ -338,7 +426,7 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) top: (p1CenterY + p2CenterY) / 2, ...textOptions, }) - // canvas.add(distanceText) + canvas.add(distanceText) let distance2 = 0 let distance3 = 0 @@ -355,13 +443,13 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) top: (p2CenterY + p3.y) / 2, ...textOptions, }) - // canvas.add(distanceText) + canvas.add(distanceText) distanceText = new fabric.Text(`${distance3 * 10}`, { left: (p3.x + p1CenterX) / 2, top: (p3.y + p1CenterY) / 2, ...textOptions, }) - // canvas.add(distanceText) + canvas.add(distanceText) } const id = uuidv4() @@ -375,9 +463,16 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) vertical: distance2 * 10, diagonal: distance1 * 10, }} + deleteDistance={closeDistancePopup} />, ) + if (setCommonUtilsState) + setCommonUtilsState({ + ...commonUtils, + distance: false, + }) + // 거리 계산 후, 다음 측정을 위해 초기화 points = [] } @@ -387,8 +482,34 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) }) } } + + //텍스트 모드일때 엔터 이벤트 + addDocumentEventListener('keydown', document, (e) => { + if (e.key === 'Enter') { + const activeObject = canvas.getActiveObject() + if (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 = { ...commonFunctionState } + let tempStates = { ...commonUtils } if (tempStates[mode]) { tempStates[mode] = false @@ -402,11 +523,258 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) } } - if (setCommonFunctionState) setCommonFunctionState(tempStates) + 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)) + } + } + } + + const commonMoveObject = (obj) => { + if (obj) { + obj.set({ + lockMovementX: false, + lockMovementY: false, + }) + + addCanvasMouseEventListener('mouse:up', (e) => { + obj.set({ + lockMovementX: true, + lockMovementY: true, + }) + initEvent() + }) + + obj.setCoords() + canvas?.renderAll() + } + } + + const commonCopyObject = (obj) => { + if (obj) { + let clonedObj = null + + console.log(obj) + + obj.clone((cloned) => { + clonedObj = cloned + }) + + 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(), //복사된 객체라 새로 따준다 + }) + initEvent() + }) + } + } + + const editText = () => { + const obj = canvas?.getActiveObject() + obj.set({ editable: true }) + obj.enterEditing() + } + + const deleteObject = () => { + const obj = canvas?.getActiveObject() + commonDeleteText(obj) + } + + 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) + } + + const changeDimensionExtendLine = () => { + const group = canvas?.getActiveObject() + const id = group.id + const textObj = canvas?.getObjects().filter((obj) => obj.name === 'dimensionLineText' && obj.id === id)[0] + const items = group._objects + const originLineDirection = group.lineDirection + + let groupObj = [] + + canvas?.remove(group) + + items.forEach((item) => { + item.set({ + selectable: true, + }) + canvas?.add(item) + }) + canvas?.renderAll() + + 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 + + const lineOptions = { + stroke: dimensionSettings.color, + strokeWidth: dimensionSettings.pixel, + selectable: true, + originX: 'center', + originY: 'center', + } + + 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, + }) + + centerLine.setCoords() + canvas?.renderAll() + + const differenceY = centerLine.y1 - originY + + arrows.forEach((arrow) => { + canvas?.remove(arrow) + }) + + const { paddingX, paddingX2, paddingY, paddingY2, angle1, angle2 } = calcDimensionPosition( + originLineDirection, + centerLine.x1, + pointer.y, + centerLine.x2, + pointer.y, + ) + + const newArrow1 = createDimensionArrow(paddingX, paddingY, angle1, id) + const newArraw2 = createDimensionArrow(paddingX2, paddingY2, angle2, id) + canvas?.add(newArrow1, newArraw2) + + groupObj.push(centerLine, newArrow1, newArraw2) + + extendLine.forEach((line) => canvas?.remove(line)) + + const newExtendLine = createDimensionExtendLine(centerLine, originLineDirection, differenceY) + + newExtendLine.forEach((line) => { + const extendLine = new fabric.Line(line, { ...lineOptions, name: 'extendLine', id: id }) + canvas.add(extendLine) + groupObj.push(extendLine) + }) + + textObj.set({ + top: pointer.y + 15, + }) + textObj.setCoords() + } else { + centerLine.set({ + x1: pointer.x, + y1: centerLine.y1, + x2: pointer.x, + y2: centerLine.y2, + }) + + centerLine.setCoords() + canvas?.renderAll() + + const differenceX = centerLine.x1 - originX + + arrows.forEach((arrow) => { + canvas?.remove(arrow) + }) + + const { paddingX, paddingX2, paddingY, paddingY2, angle1, angle2 } = calcDimensionPosition( + originLineDirection, + pointer.x, + centerLine.y1, + pointer.x, + centerLine.y2, + ) + + const newArrow1 = createDimensionArrow(paddingX, paddingY, angle1, id) + const newArraw2 = createDimensionArrow(paddingX2, paddingY2, angle2, id) + canvas?.add(newArrow1, newArraw2) + + groupObj.push(centerLine, newArrow1, newArraw2) + + extendLine.forEach((line) => canvas?.remove(line)) + + const newExtendLine = createDimensionExtendLine(centerLine, originLineDirection, differenceX) + + newExtendLine.forEach((line) => { + const extendLine = new fabric.Line(line, { ...lineOptions, name: 'extendLine', id: id }) + canvas.add(extendLine) + groupObj.push(extendLine) + }) + + textObj.set({ + left: pointer.x - 15, + }) + textObj.setCoords() + } + + const reGroup = new fabric.Group(groupObj, { + name: 'dimensionLine', + selectable: true, + originX: 'center', + originY: 'center', + lineDirection: originLineDirection, + id: id, + }) + canvas.add(reGroup) + initEvent() + }) } return { commonFunctions, dimensionSettings, + commonDeleteText, + commonMoveObject, + commonDeleteText, + deleteObject, + moveObject, + copyObject, + editText, + changeDimensionExtendLine, } } diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index bbd5115b..adb9b680 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -20,6 +20,8 @@ import DimensionLineSetting from '@/components/floor-plan/modal/dimensionLine/Di import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting' import LinePropertySetting from '@/components/floor-plan/modal/lineProperty/LinePropertySetting' import FlowDirectionSetting from '@/components/floor-plan/modal/flowDirection/FlowDirectionSetting' +import { useCommonUtils } from './common/useCommonUtils' +import { canvasState } from '@/store/canvasAtom' export function useContextMenu({ externalFn }) { const currentMenu = useRecoilValue(currentMenuState) // 현재 메뉴 @@ -30,6 +32,9 @@ export function useContextMenu({ externalFn }) { const { addPopup } = usePopup() const [popupId, setPopupId] = useState(uuidv4()) const [gridColor, setGridColor] = useRecoilState(gridColorState) + const canvas = useRecoilValue(canvasState) + const { deleteObject, moveObject, copyObject, editText, changeDimensionExtendLine } = useCommonUtils({}) + const currentMenuSetting = (position) => { switch (currentMenu) { case MENU.PLAN_DRAWING: @@ -200,7 +205,7 @@ export function useContextMenu({ externalFn }) { }, [currentContextMenu]) useEffect(() => { - console.log('object name', currentObject?.name) + console.log('object name', currentObject) if (currentObject?.name) { switch (currentObject.name) { case 'triangleDormer': @@ -331,14 +336,17 @@ export function useContextMenu({ externalFn }) { { id: 'commonTextRemove', name: '삭제', + fn: () => deleteObject(), }, { id: 'commonTextMove', name: '이동', + fn: () => moveObject(), }, { id: 'commonTextCopy', name: '복사', + fn: () => copyObject(), }, { id: 'commonTextFontSetting', @@ -348,6 +356,7 @@ export function useContextMenu({ externalFn }) { { id: 'commonTextEdit', name: '편집', + fn: () => editText(), }, ], ]) @@ -384,14 +393,17 @@ export function useContextMenu({ externalFn }) { { id: 'dimensionLineRemove', name: '삭제', + fn: () => deleteObject(), }, { id: 'dimensionLineMove', name: '이동', + fn: () => moveObject(), }, { id: 'dimensionAuxiliaryLineEdit', name: '치수 보조선 변경', + fn: () => changeDimensionExtendLine(), }, { id: 'dimensionLineDisplayEdit', diff --git a/src/store/commonUtilsAtom.js b/src/store/commonUtilsAtom.js index 3fe8dbb7..545f8196 100644 --- a/src/store/commonUtilsAtom.js +++ b/src/store/commonUtilsAtom.js @@ -1,5 +1,11 @@ import { atom } from 'recoil' +const defaultUtils = { + text: false, + dimension: false, + distance: false, +} + export const dimensionLineSettingsState = atom({ key: 'dimensionLineSettingsState', default: { @@ -11,3 +17,8 @@ export const dimensionLineSettingsState = atom({ fontStyle: 'normal', }, }) + +export const commonUtilsState = atom({ + key: 'commonUtilsState', + default: defaultUtils, +})