치수선 보조선 변경 추가

This commit is contained in:
yjnoh 2024-10-28 13:11:32 +09:00
parent fc13c39fa4
commit 9353fad3aa
6 changed files with 496 additions and 101 deletions

View File

@ -11,11 +11,16 @@ import { currentObjectState } from '@/store/canvasAtom'
import { useCanvasEvent } from '@/hooks/useCanvasEvent' import { useCanvasEvent } from '@/hooks/useCanvasEvent'
import QContextMenu from '@/components/common/context-menu/QContextMenu' import QContextMenu from '@/components/common/context-menu/QContextMenu'
import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize' 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 }) { export default function CanvasFrame({ plan }) {
const canvasRef = useRef(null) const canvasRef = useRef(null)
const { canvas } = useCanvas('canvas') const { canvas } = useCanvas('canvas')
const { handleZoomClear } = useCanvasEvent() const { handleZoomClear } = useCanvasEvent()
const { testAlert } = useCommonUtils({})
const { contextMenu, currentContextMenu, setCurrentContextMenu, handleClick } = useContextMenu({ const { contextMenu, currentContextMenu, setCurrentContextMenu, handleClick } = useContextMenu({
externalFn: { externalFn: {
handleZoomClear, handleZoomClear,

View File

@ -27,6 +27,7 @@ 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' import { useCommonUtils } from '@/hooks/common/useCommonUtils'
import { commonUtilsState } from '@/store/commonUtilsAtom'
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 },
@ -61,17 +62,8 @@ export default function CanvasMenu(props) {
const { saveCanvas } = usePlan() const { saveCanvas } = usePlan()
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useEvent() const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useEvent()
const commonUtils = useRecoilValue(commonUtilsState)
const [commonFunctionState, setCommonFunctionState] = useState({ const { commonFunctions } = useCommonUtils()
text: false,
dimension: false,
distance: false,
})
const { commonFunctions } = useCommonUtils({
commonFunctionState,
setCommonFunctionState,
})
const [popup, setPopup] = useRecoilState(popupState) const [popup, setPopup] = useRecoilState(popupState)
@ -188,9 +180,9 @@ export default function CanvasMenu(props) {
</div> </div>
} }
<div className="btn-from"> <div className="btn-from">
<button className={`btn01 ${commonFunctionState.text ? 'active' : ''}`} onClick={() => commonFunctions('text')}></button> <button className={`btn01 ${commonUtils.text ? 'active' : ''}`} onClick={() => commonFunctions('text')}></button>
<button className={`btn02 ${commonFunctionState.dimension ? 'active' : ''} `} onClick={() => commonFunctions('dimension')}></button> <button className={`btn02 ${commonUtils.dimension ? 'active' : ''} `} onClick={() => commonFunctions('dimension')}></button>
<button className={`btn03 ${commonFunctionState.distance ? 'active' : ''} `} onClick={() => commonFunctions('distance')}></button> <button className={`btn03 ${commonUtils.distance ? 'active' : ''} `} onClick={() => commonFunctions('distance')}></button>
</div> </div>
<div className="select-box"> <div className="select-box">
<QSelectBox title={'瓦53A'} option={SelectOption} /> <QSelectBox title={'瓦53A'} option={SelectOption} />

View File

@ -1,15 +1,20 @@
import WithDraggable from '@/components/common/draggable/withDraggable' import { useRecoilValue } from 'recoil'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { useRecoilValue } from 'recoil' import WithDraggable from '@/components/common/draggable/WithDraggable'
import { contextPopupPositionState } from '@/store/popupAtom' import { contextPopupPositionState } from '@/store/popupAtom'
export default function Distance(props) { export default function Distance(props) {
const contextPopupPosition = useRecoilValue(contextPopupPositionState) const contextPopupPosition = useRecoilValue(contextPopupPositionState)
const { id, pos = contextPopupPosition, distance } = props const { id, pos = contextPopupPosition, distance, deleteDistance } = props
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { closePopup } = usePopup() const { closePopup } = usePopup()
const handleClose = () => {
deleteDistance()
closePopup(id)
}
return ( return (
<WithDraggable isShow={true} pos={pos}> <WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xxxm`}> <div className={`modal-pop-wrap xxxm`}>
@ -58,7 +63,9 @@ export default function Distance(props) {
</div> </div>
</div> </div>
<div className="grid-btn-wrap"> <div className="grid-btn-wrap">
<button className="btn-frame modal act">確認</button> <button className="btn-frame modal act" onClick={handleClose}>
確認
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
import { useEffect } from 'react' import { useEffect } from 'react'
import { useRecoilValue } from 'recoil' import { useRecoilValue, useRecoilState } from 'recoil'
import { wordDisplaySelector } from '@/store/settingAtom' import { wordDisplaySelector } from '@/store/settingAtom'
import { useEvent } from '@/hooks/useEvent' import { useEvent } from '@/hooks/useEvent'
import { checkLineOrientation, getDistance } from '@/util/canvas-util' import { checkLineOrientation, getDistance } from '@/util/canvas-util'
@ -9,30 +9,34 @@ import { canvasState } from '@/store/canvasAtom'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import Distance from '@/components/floor-plan/modal/distance/Distance' 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 canvas = useRecoilValue(canvasState)
const wordDisplay = useRecoilValue(wordDisplaySelector) const wordDisplay = useRecoilValue(wordDisplaySelector)
const { addCanvasMouseEventListener, addDocumentEventListener, initEvent } = useEvent() const { addCanvasMouseEventListener, addDocumentEventListener, initEvent } = useEvent()
const dimensionSettings = useRecoilValue(dimensionLineSettingsState) const dimensionSettings = useRecoilValue(dimensionLineSettingsState)
const dimensionLineTextFont = useRecoilValue(fontSelector('dimensionLineText')) const dimensionLineTextFont = useRecoilValue(fontSelector('dimensionLineText'))
const commonTextFont = useRecoilValue(fontSelector('commonText')) const commonTextFont = useRecoilValue(fontSelector('commonText'))
const [commonUtils, setCommonUtilsState] = useRecoilState(commonUtilsState)
const { addPopup } = usePopup() const { addPopup } = usePopup()
useEffect(() => { useEffect(() => {
initEvent() initEvent()
if (commonFunctionState.text) { if (commonUtils.text) {
commonTextMode() commonTextMode()
} else if (commonFunctionState.dimension) { } else if (commonUtils.dimension) {
commonDimensionMode() commonDimensionMode()
} else if (commonFunctionState.distance) { } else if (commonUtils.distance) {
commonDistanceMode() commonDistanceMode()
} }
}, [commonFunctionState, dimensionSettings, commonTextFont, dimensionLineTextFont]) }, [commonUtils, dimensionSettings, commonTextFont, dimensionLineTextFont])
const commonTextMode = () => { const commonTextMode = () => {
let textbox let textbox
if (commonFunctionState.text) { if (commonUtils.text) {
addCanvasMouseEventListener('mouse:down', (event) => { addCanvasMouseEventListener('mouse:down', (event) => {
const pointer = canvas?.getPointer(event.e) const pointer = canvas?.getPointer(event.e)
textbox = new fabric.Textbox('', { textbox = new fabric.Textbox('', {
@ -46,6 +50,11 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState })
fontFamily: commonTextFont.fontFamily.value, fontFamily: commonTextFont.fontFamily.value,
fontSize: commonTextFont.fontSize.value, fontSize: commonTextFont.fontSize.value,
fontStyle: commonTextFont.fontWeight.value, fontStyle: commonTextFont.fontWeight.value,
selectable: true,
lockMovementX: true,
lockMovementY: true,
originX: 'center',
originY: 'center',
}) })
canvas?.add(textbox) canvas?.add(textbox)
@ -53,70 +62,120 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState })
textbox.enterEditing() textbox.enterEditing()
textbox.selectAll() textbox.selectAll()
}) })
}
}
addDocumentEventListener('keydown', document, (e) => { const createDimensionArrow = (x, y, angle, id) => {
if (e.key === 'Enter') { return new fabric.Triangle({
if (commonFunctionState.text) { left: x,
const activeObject = canvas.getActiveObject() top: y,
if (activeObject && activeObject.isEditing) { originX: 'center',
if (activeObject.text === '') { originY: 'center',
canvas?.remove(activeObject) angle: angle,
} else { width: 15,
activeObject.exitEditing() height: 15,
} fill: dimensionSettings.color,
//정책 협의 selectable: true,
const texts = canvas.getObjects().filter((obj) => obj.name === 'commonText') name: 'arrow',
texts.forEach((text) => { id: id,
text.set({ editable: false }) })
}) }
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 = () => { const commonDimensionMode = () => {
if (commonFunctionState.dimension) { if (commonUtils.dimension) {
const uuid = uuidv4()
let points = [] let points = []
let distanceText = null let distanceText = null
let minX, minY, maxX, maxY 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 = { const circleOptions = {
radius: 5, radius: 5,
strokeWidth: 2, strokeWidth: 2,
stroke: 'red', stroke: 'red',
fill: 'white', fill: 'white',
selectable: false, selectable: true,
} }
const lineOptions = { const lineOptions = {
stroke: dimensionSettings.color, stroke: dimensionSettings.color,
strokeWidth: dimensionSettings.pixel, strokeWidth: dimensionSettings.pixel,
name: 'dimensionLine',
selectable: true, selectable: true,
originX: 'center',
originY: 'center',
} }
// 캔버스에 클릭 이벤트 추가 // 캔버스에 클릭 이벤트 추가
addCanvasMouseEventListener('mouse:down', (e) => { addCanvasMouseEventListener('mouse:down', (e) => {
let groupObjects = []
const pointer = canvas.getPointer(e.e) const pointer = canvas.getPointer(e.e)
let point let point
if (points.length === 0) { 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) canvas.add(line)
// groupObjects.push(line)
const distance = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY) const distance = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY)
const lineDirection = checkLineOrientation(line) const lineDirection = checkLineOrientation(line)
let extendLine = []
if (lineDirection === 'horizontal') { const extendListArray = createDimensionExtendLine(line, lineDirection)
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) => { extendListArray.forEach((line) => {
const extendLine = new fabric.Line(line, lineOptions) const extendLine = new fabric.Line(line, { ...lineOptions, name: 'extendLine', id: uuid })
canvas.add(extendLine) // canvas.add(extendLine)
groupObjects.push(extendLine)
}) })
// 첫 번째 포인트에 화살표 추가 // // 첫 번째 포인트에 화살표 추가 좌측 -> 우측으로 그릴때
const paddingX = lineDirection === 'horizontal' ? p1CenterX + 7.5 : p1CenterX + 1 // let paddingX = lineDirection === 'horizontal' ? p1CenterX + 7.5 : p1CenterX + 0.5
const paddingX2 = lineDirection === 'horizontal' ? p2CenterX - 6.5 : p2CenterX + 1 // let paddingX2 = lineDirection === 'horizontal' ? p2CenterX - 7.5 : p2CenterX + 0.5
const paddingY = lineDirection === 'horizontal' ? p1CenterY + 1 : p1CenterY + 8 // let paddingY = lineDirection === 'horizontal' ? p1CenterY + 0.5 : p1CenterY + 8
const paddingY2 = lineDirection === 'horizontal' ? p2CenterY + 1 : p2CenterY - 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) // 정방향 화살표 // if (paddingX > paddingX2 || paddingY > paddingY2) {
canvas.add(arrow1) // paddingX = lineDirection === 'horizontal' ? p1CenterX - 7.5 : p1CenterX + 0.5
canvas.add(arrow2) // 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} `, { distanceText = new fabric.Text(`${distance * 10} `, {
left: (p1CenterX + p2CenterX) / 2 + (lineDirection === 'horizontal' ? 0 : -15), left: (p1CenterX + p2CenterX) / 2 + (lineDirection === 'horizontal' ? 0 : -15),
@ -213,18 +292,24 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState })
originY: 'center', originY: 'center',
angle: lineDirection === 'horizontal' ? 0 : 270, angle: lineDirection === 'horizontal' ? 0 : 270,
name: 'dimensionLineText', name: 'dimensionLineText',
id: uuid,
// lockMovementX: false, // lockMovementX: false,
// lockMovementY: false, // lockMovementY: false,
}) })
canvas.add(distanceText) canvas.add(distanceText)
// minX = p1CenterX // groupObjects.push(distanceText)
// maxX = p2CenterX
// minY = p1CenterY canvas.renderAll()
// maxY = p2CenterY
// 거리 계산 후, 다음 측정을 위해 초기화 // 거리 계산 후, 다음 측정을 위해 초기화
points = [] points = []
if (setCommonUtilsState)
setCommonUtilsState({
...commonUtilsState,
dimension: false,
})
} }
// 캔버스 다시 그리기 // 캔버스 다시 그리기
@ -251,7 +336,7 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState })
} }
const commonDistanceMode = () => { const commonDistanceMode = () => {
if (commonFunctionState.distance) { if (commonUtils.distance) {
let points = [] let points = []
let distanceText = null let distanceText = null
let drawPoints = [] let drawPoints = []
@ -261,13 +346,15 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState })
strokeWidth: 1, strokeWidth: 1,
originX: 'center', originX: 'center',
originY: 'center', originY: 'center',
name: 'distance',
} }
const lineOptions = { const lineOptions = {
stroke: 'black', stroke: 'black',
strokeWidth: 2, strokeWidth: 1,
selectable: false, selectable: false,
strokeDashArray: [9, 5], strokeDashArray: [10, 5],
name: 'distance',
} }
const textOptions = { const textOptions = {
@ -277,11 +364,12 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState })
textAlign: 'center', textAlign: 'center',
originX: 'center', originX: 'center',
originY: 'center', originY: 'center',
name: 'distance',
} }
// 캔버스에 클릭 이벤트 추가 // 캔버스에 클릭 이벤트 추가
addCanvasMouseEventListener('mouse:down', function (options) { addCanvasMouseEventListener('mouse:down', function (e) {
const pointer = canvas.getPointer(options.e) const pointer = canvas.getPointer(e.e)
let point let point
let cross = {} let cross = {}
@ -338,7 +426,7 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState })
top: (p1CenterY + p2CenterY) / 2, top: (p1CenterY + p2CenterY) / 2,
...textOptions, ...textOptions,
}) })
// canvas.add(distanceText) canvas.add(distanceText)
let distance2 = 0 let distance2 = 0
let distance3 = 0 let distance3 = 0
@ -355,13 +443,13 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState })
top: (p2CenterY + p3.y) / 2, top: (p2CenterY + p3.y) / 2,
...textOptions, ...textOptions,
}) })
// canvas.add(distanceText) canvas.add(distanceText)
distanceText = new fabric.Text(`${distance3 * 10}`, { distanceText = new fabric.Text(`${distance3 * 10}`, {
left: (p3.x + p1CenterX) / 2, left: (p3.x + p1CenterX) / 2,
top: (p3.y + p1CenterY) / 2, top: (p3.y + p1CenterY) / 2,
...textOptions, ...textOptions,
}) })
// canvas.add(distanceText) canvas.add(distanceText)
} }
const id = uuidv4() const id = uuidv4()
@ -375,9 +463,16 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState })
vertical: distance2 * 10, vertical: distance2 * 10,
diagonal: distance1 * 10, diagonal: distance1 * 10,
}} }}
deleteDistance={closeDistancePopup}
/>, />,
) )
if (setCommonUtilsState)
setCommonUtilsState({
...commonUtils,
distance: false,
})
// 거리 계산 후, 다음 측정을 위해 초기화 // 거리 계산 후, 다음 측정을 위해 초기화
points = [] 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) => { const commonFunctions = (mode) => {
let tempStates = { ...commonFunctionState } let tempStates = { ...commonUtils }
if (tempStates[mode]) { if (tempStates[mode]) {
tempStates[mode] = false 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 { return {
commonFunctions, commonFunctions,
dimensionSettings, dimensionSettings,
commonDeleteText,
commonMoveObject,
commonDeleteText,
deleteObject,
moveObject,
copyObject,
editText,
changeDimensionExtendLine,
} }
} }

View File

@ -20,6 +20,8 @@ import DimensionLineSetting from '@/components/floor-plan/modal/dimensionLine/Di
import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting' import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting'
import LinePropertySetting from '@/components/floor-plan/modal/lineProperty/LinePropertySetting' import LinePropertySetting from '@/components/floor-plan/modal/lineProperty/LinePropertySetting'
import FlowDirectionSetting from '@/components/floor-plan/modal/flowDirection/FlowDirectionSetting' import FlowDirectionSetting from '@/components/floor-plan/modal/flowDirection/FlowDirectionSetting'
import { useCommonUtils } from './common/useCommonUtils'
import { canvasState } from '@/store/canvasAtom'
export function useContextMenu({ externalFn }) { export function useContextMenu({ externalFn }) {
const currentMenu = useRecoilValue(currentMenuState) // 현재 메뉴 const currentMenu = useRecoilValue(currentMenuState) // 현재 메뉴
@ -30,6 +32,9 @@ export function useContextMenu({ externalFn }) {
const { addPopup } = usePopup() const { addPopup } = usePopup()
const [popupId, setPopupId] = useState(uuidv4()) const [popupId, setPopupId] = useState(uuidv4())
const [gridColor, setGridColor] = useRecoilState(gridColorState) const [gridColor, setGridColor] = useRecoilState(gridColorState)
const canvas = useRecoilValue(canvasState)
const { deleteObject, moveObject, copyObject, editText, changeDimensionExtendLine } = useCommonUtils({})
const currentMenuSetting = (position) => { const currentMenuSetting = (position) => {
switch (currentMenu) { switch (currentMenu) {
case MENU.PLAN_DRAWING: case MENU.PLAN_DRAWING:
@ -200,7 +205,7 @@ export function useContextMenu({ externalFn }) {
}, [currentContextMenu]) }, [currentContextMenu])
useEffect(() => { useEffect(() => {
console.log('object name', currentObject?.name) console.log('object name', currentObject)
if (currentObject?.name) { if (currentObject?.name) {
switch (currentObject.name) { switch (currentObject.name) {
case 'triangleDormer': case 'triangleDormer':
@ -331,14 +336,17 @@ export function useContextMenu({ externalFn }) {
{ {
id: 'commonTextRemove', id: 'commonTextRemove',
name: '삭제', name: '삭제',
fn: () => deleteObject(),
}, },
{ {
id: 'commonTextMove', id: 'commonTextMove',
name: '이동', name: '이동',
fn: () => moveObject(),
}, },
{ {
id: 'commonTextCopy', id: 'commonTextCopy',
name: '복사', name: '복사',
fn: () => copyObject(),
}, },
{ {
id: 'commonTextFontSetting', id: 'commonTextFontSetting',
@ -348,6 +356,7 @@ export function useContextMenu({ externalFn }) {
{ {
id: 'commonTextEdit', id: 'commonTextEdit',
name: '편집', name: '편집',
fn: () => editText(),
}, },
], ],
]) ])
@ -384,14 +393,17 @@ export function useContextMenu({ externalFn }) {
{ {
id: 'dimensionLineRemove', id: 'dimensionLineRemove',
name: '삭제', name: '삭제',
fn: () => deleteObject(),
}, },
{ {
id: 'dimensionLineMove', id: 'dimensionLineMove',
name: '이동', name: '이동',
fn: () => moveObject(),
}, },
{ {
id: 'dimensionAuxiliaryLineEdit', id: 'dimensionAuxiliaryLineEdit',
name: '치수 보조선 변경', name: '치수 보조선 변경',
fn: () => changeDimensionExtendLine(),
}, },
{ {
id: 'dimensionLineDisplayEdit', id: 'dimensionLineDisplayEdit',

View File

@ -1,5 +1,11 @@
import { atom } from 'recoil' import { atom } from 'recoil'
const defaultUtils = {
text: false,
dimension: false,
distance: false,
}
export const dimensionLineSettingsState = atom({ export const dimensionLineSettingsState = atom({
key: 'dimensionLineSettingsState', key: 'dimensionLineSettingsState',
default: { default: {
@ -11,3 +17,8 @@ export const dimensionLineSettingsState = atom({
fontStyle: 'normal', fontStyle: 'normal',
}, },
}) })
export const commonUtilsState = atom({
key: 'commonUtilsState',
default: defaultUtils,
})