임의 그리드모드 추가

This commit is contained in:
hyojun.choi 2024-08-28 16:19:27 +09:00
parent 5cf29ec019
commit 06180dae94
3 changed files with 241 additions and 210 deletions

View File

@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react'
import { Button, Checkbox, CheckboxGroup, RadioGroup, Radio, Input } from '@nextui-org/react' import { Button, Checkbox, CheckboxGroup, RadioGroup, Radio, Input } from '@nextui-org/react'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
import { modalContent, modalState } from '@/store/modalAtom' import { modalContent, modalState } from '@/store/modalAtom'
import { guideLineState } from '@/store/canvasAtom' import { guideLineState, horiGuideLinesState, vertGuideLinesState } from '@/store/canvasAtom'
import { fabric } from 'fabric' import { fabric } from 'fabric'
export default function SettingsModal(props) { export default function SettingsModal(props) {
@ -16,6 +16,8 @@ export default function SettingsModal(props) {
const [open, setOpen] = useRecoilState(modalState) const [open, setOpen] = useRecoilState(modalState)
const [guideLine, setGuideLine] = useRecoilState(guideLineState) const [guideLine, setGuideLine] = useRecoilState(guideLineState)
const [horiGuideLines, setHoriGuideLines] = useRecoilState(horiGuideLinesState)
const [vertGuideLines, setVertGuideLines] = useRecoilState(vertGuideLinesState)
const gridSettingArray = [] const gridSettingArray = []
@ -63,6 +65,7 @@ export default function SettingsModal(props) {
lockScalingX: true, lockScalingX: true,
lockScalingY: true, lockScalingY: true,
name: 'guideLine', name: 'guideLine',
direction: 'horizontal',
}, },
) )
canvasProps.add(horizontalLine) canvasProps.add(horizontalLine)
@ -82,6 +85,7 @@ export default function SettingsModal(props) {
lockScalingX: true, lockScalingX: true,
lockScalingY: true, lockScalingY: true,
name: 'guideLine', name: 'guideLine',
direction: 'vertical',
}, },
) )
canvasProps.add(verticalLine) canvasProps.add(verticalLine)
@ -99,6 +103,16 @@ export default function SettingsModal(props) {
moduleHoriLength: moduleHoriLength, moduleHoriLength: moduleHoriLength,
} }
gridSettingArray.push(recoilObj) gridSettingArray.push(recoilObj)
const newHoriGuideLines = [...horiGuideLines]
horizontalLineArray.forEach((line) => {
newHoriGuideLines.push(line)
})
const newVertGuideLines = [...vertGuideLines]
verticalLineArray.forEach((line) => {
newVertGuideLines.push(line)
})
setHoriGuideLines(newHoriGuideLines)
setVertGuideLines(newVertGuideLines)
} }
if (gridCheckedValue.includes('dot')) { if (gridCheckedValue.includes('dot')) {
@ -170,6 +184,8 @@ export default function SettingsModal(props) {
guideLines?.forEach((item) => canvasProps.remove(item)) guideLines?.forEach((item) => canvasProps.remove(item))
canvasProps.renderAll() canvasProps.renderAll()
setGuideLine([]) setGuideLine([])
setHoriGuideLines([])
setVertGuideLines([])
} else { } else {
alert('그리드가 없습니다.') alert('그리드가 없습니다.')
return return

View File

@ -25,6 +25,8 @@ import {
templateTypeState, templateTypeState,
wallState, wallState,
guideLineState, guideLineState,
horiGuideLinesState,
vertGuideLinesState,
} from '@/store/canvasAtom' } from '@/store/canvasAtom'
import { QLine } from '@/components/fabric/QLine' import { QLine } from '@/components/fabric/QLine'
import { fabric } from 'fabric' import { fabric } from 'fabric'
@ -69,8 +71,8 @@ export function useMode() {
const [guideLineMode, setGuideLineMode] = useState(false) const [guideLineMode, setGuideLineMode] = useState(false)
const [guideDotMode, setGuideDotMode] = useState(false) const [guideDotMode, setGuideDotMode] = useState(false)
const [horiGuideLines, setHoriGuideLines] = useState([]) const [horiGuideLines, setHoriGuideLines] = useRecoilState(horiGuideLinesState)
const [vertGuideLines, setVertGuideLines] = useState([]) const [vertGuideLines, setVertGuideLines] = useRecoilState(vertGuideLinesState)
useEffect(() => { useEffect(() => {
// if (!canvas) { // if (!canvas) {
@ -99,10 +101,10 @@ export function useMode() {
}, [endPoint]) }, [endPoint])
useEffect(() => { useEffect(() => {
changeMode(canvas, mode)
canvas?.off('mouse:move') canvas?.off('mouse:move')
canvas?.on('mouse:move', drawMouseLines) canvas?.on('mouse:move', drawMouseLines)
changeMode(canvas, mode) }, [mode, horiGuideLines, vertGuideLines])
}, [mode])
useEffect(() => { useEffect(() => {
setGuideLineMode(false) setGuideLineMode(false)
@ -111,9 +113,6 @@ export function useMode() {
const guideLineState = guideLineInfo.filter((item) => item.guideMode === 'guideLine') const guideLineState = guideLineInfo.filter((item) => item.guideMode === 'guideLine')
const guideDotState = guideLineInfo.filter((item) => item.guideMode === 'guideDot') const guideDotState = guideLineInfo.filter((item) => item.guideMode === 'guideDot')
setHoriGuideLines(guideLineState[0].horizontalLineArray)
setVertGuideLines(guideLineState[0].verticalLineArray)
setGuideLineMode(guideLineState.length > 0) setGuideLineMode(guideLineState.length > 0)
setGuideDotMode(guideDotState.length > 0) setGuideDotMode(guideDotState.length > 0)
} }
@ -160,12 +159,8 @@ export function useMode() {
if (mode === Mode.EDIT || mode === Mode.ADSORPTION_POINT) { if (mode === Mode.EDIT || mode === Mode.ADSORPTION_POINT) {
let adsorptionPoint = adsorptionPointList.length > 0 ? findClosestPoint(pointer, adsorptionPointList) : null let adsorptionPoint = adsorptionPointList.length > 0 ? findClosestPoint(pointer, adsorptionPointList) : null
if (isGuideLineMode && isGuideDotMode) { if ((horiGuideLines.length > 0 || vertGuideLines.length > 0) && guideDotMode) {
const closestHorizontalLine = getClosestHorizontalLine(pointer, horizontalLineArray) } else if (guideDotMode) {
const closetVerticalLine = getClosestVerticalLine(pointer, verticalLineArray)
const xDiff = Math.abs(pointer.x - closetVerticalLine.x1)
const yDiff = Math.abs(pointer.y - closestHorizontalLine.y1)
const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori) const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori)
const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert) const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert)
@ -177,35 +172,28 @@ export function useMode() {
if (isAttachX && isAttachY) { if (isAttachX && isAttachY) {
newX = Math.floor(pointer.x / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2 newX = Math.floor(pointer.x / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2
newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2 newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2
} else { }
if (Math.min(xDiff, yDiff) <= 20) { } else if (horiGuideLines.length > 0 || vertGuideLines.length > 0) {
if (xDiff < yDiff) { const closestHorizontalLine = getClosestHorizontalLine(pointer, horiGuideLines)
newX = closetVerticalLine.x1 const closetVerticalLine = getClosestVerticalLine(pointer, vertGuideLines)
newY = pointer.y let intersection = null
} else { let intersectionDistance = Infinity
newX = pointer.x
newY = closestHorizontalLine.y1 if (closestHorizontalLine && closetVerticalLine) {
} intersection = calculateIntersection(closestHorizontalLine, closetVerticalLine)
if (intersection) {
intersectionDistance = distanceBetweenPoints(pointer, intersection)
} }
} }
} else if (isGuideDotMode) {
const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori)
const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert)
const xRate = x / guideLineLengthHori let xDiff, yDiff
const yRate = y / guideLineLengthVert
const isAttachX = xRate >= 0.4 && xRate <= 0.7
const isAttachY = yRate >= 0.4 && yRate <= 0.7
if (isAttachX && isAttachY) { if (closetVerticalLine) {
newX = Math.floor(pointer.x / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2 xDiff = Math.abs(pointer.x - closetVerticalLine.x1)
newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2 }
if (closestHorizontalLine) {
yDiff = Math.abs(pointer.y - closestHorizontalLine.y1)
} }
} else if (isGuideLineMode) {
const closestHorizontalLine = getClosestHorizontalLine(pointer, horizontalLineArray)
const closetVerticalLine = getClosestVerticalLine(pointer, verticalLineArray)
const xDiff = Math.abs(pointer.x - closetVerticalLine.x1)
const yDiff = Math.abs(pointer.y - closestHorizontalLine.y1)
const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori) const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori)
const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert) const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert)
@ -214,23 +202,26 @@ export function useMode() {
const yRate = y / guideLineLengthVert const yRate = y / guideLineLengthVert
const isAttachX = xRate >= 0.4 && xRate <= 0.7 const isAttachX = xRate >= 0.4 && xRate <= 0.7
const isAttachY = yRate >= 0.4 && yRate <= 0.7 const isAttachY = yRate >= 0.4 && yRate <= 0.7
if (isAttachX && isAttachY) { if (isAttachX && isAttachY) {
newX = Math.floor(pointer.x / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2 newX = Math.floor(pointer.x / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2
newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2 newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2
} else { } else {
if (Math.min(xDiff, yDiff) <= 20) { if (intersection && intersectionDistance < 20) {
if (xDiff < yDiff) { newX = intersection.x
newX = closetVerticalLine.x1 newY = intersection.y
newY = pointer.y } else {
} else { if (Math.min(xDiff, yDiff) <= 20) {
newX = pointer.x if (xDiff < yDiff) {
newY = closestHorizontalLine.y1 newX = closetVerticalLine.x1
newY = pointer.y
} else {
newX = pointer.x
newY = closestHorizontalLine.y1
}
} }
} }
} }
} }
if (adsorptionPoint && distanceBetweenPoints(pointer, adsorptionPoint) < 20) { if (adsorptionPoint && distanceBetweenPoints(pointer, adsorptionPoint) < 20) {
newX = adsorptionPoint.left newX = adsorptionPoint.left
newY = adsorptionPoint.top newY = adsorptionPoint.top
@ -358,8 +349,6 @@ export function useMode() {
// 모드에 따른 마우스 이벤트 변경 // 모드에 따른 마우스 이벤트 변경
const changeMouseEvent = (mode) => { const changeMouseEvent = (mode) => {
document.removeEventListener('contextmenu', mouseEvent.drawLineModeRightClick)
switch (mode) { switch (mode) {
case 'drawLine': case 'drawLine':
canvas?.on('mouse:down', mouseEvent.drawLineModeLeftClick) canvas?.on('mouse:down', mouseEvent.drawLineModeLeftClick)
@ -367,7 +356,6 @@ export function useMode() {
break break
case 'edit': case 'edit':
canvas?.on('mouse:down', mouseEvent.editMode) canvas?.on('mouse:down', mouseEvent.editMode)
break break
case 'textbox': case 'textbox':
canvas?.on('mouse:down', mouseEvent.textboxMode) canvas?.on('mouse:down', mouseEvent.textboxMode)
@ -546,11 +534,14 @@ export function useMode() {
} }
const mouseAndkeyboardEventClear = () => { const mouseAndkeyboardEventClear = () => {
canvas?.off('mouse:down')
Object.keys(mouseEvent).forEach((key) => { Object.keys(mouseEvent).forEach((key) => {
canvas?.off('mouse:down', mouseEvent[key]) canvas?.off('mouse:down', mouseEvent[key])
document.removeEventListener('contextmenu', mouseEvent[key])
}) })
Object.keys(keyboardEvent).forEach((key) => { Object.keys(keyboardEvent).forEach((key) => {
window.removeEventListener('keydown', keyboardEvent[key]) document.removeEventListener('keydown', keyboardEvent[key])
}) })
} }
@ -558,6 +549,7 @@ export function useMode() {
// rerendering을 막기 위해 useCallback 사용 // rerendering을 막기 위해 useCallback 사용
editMode: useCallback( editMode: useCallback(
(e) => { (e) => {
e.preventDefault()
switch (e.key) { switch (e.key) {
case 'ArrowDown': { case 'ArrowDown': {
if (!keyValid()) { if (!keyValid()) {
@ -627,11 +619,12 @@ export function useMode() {
} }
const changeMode = (canvas, mode) => { const changeMode = (canvas, mode) => {
mouseAndkeyboardEventClear()
setMode(mode) setMode(mode)
setCanvas(canvas) setCanvas(canvas)
// mode별 이벤트 변경 // mode별 이벤트 변경
mouseAndkeyboardEventClear()
changeMouseEvent(mode) changeMouseEvent(mode)
changeKeyboardEvent(mode) changeKeyboardEvent(mode)
@ -670,42 +663,49 @@ export function useMode() {
if (mode === Mode.EDIT) { if (mode === Mode.EDIT) {
switch (mode) { switch (mode) {
case 'edit': case 'edit':
window.addEventListener('keydown', keyboardEvent.editMode) document.addEventListener('keydown', keyboardEvent.editMode)
break break
} }
} }
} }
const mouseEvent = { const mouseEvent = {
drawLineModeLeftClick: useCallback( drawLineModeLeftClick: (options) => {
(options) => { if (mode !== Mode.DRAW_LINE) {
const pointer = canvas?.getPointer(options.e) return
}
const pointer = canvas?.getPointer(options.e)
const line = new QLine( const line = new QLine(
[pointer.x, 0, pointer.x, canvas.height], // y축에 1자 선을 그립니다. [pointer.x, 0, pointer.x, canvasSize.vertical], // y축에 1자 선을 그립니다.
{ {
stroke: 'gray', stroke: 'gray',
strokeWidth: 1, strokeWidth: 1,
selectable: true, selectable: true,
lockMovementX: true, lockMovementX: true,
lockMovementY: true, lockMovementY: true,
lockRotation: true, lockRotation: true,
lockScalingX: true, lockScalingX: true,
lockScalingY: true, lockScalingY: true,
name: 'guideLine', name: 'guideLine',
}, direction: 'vertical',
) },
)
canvas?.add(line) canvas?.add(line)
canvas?.renderAll() canvas?.renderAll()
const newVerticalLineArray = [...vertGuideLines, line] const newVerticalLineArray = [...vertGuideLines]
setVertGuideLines(newVerticalLineArray) newVerticalLineArray.push(line)
},
[canvas, vertGuideLines], setVertGuideLines(newVerticalLineArray)
), },
drawLineModeRightClick: useCallback( drawLineModeRightClick: useCallback(
(options) => { (options) => {
document.removeEventListener('contextmenu', mouseEvent.drawLineModeRightClick)
if (mode !== Mode.DRAW_LINE) {
return
}
const line = new fabric.Line( const line = new fabric.Line(
[0, options.offsetY, canvasSize.horizontal, options.offsetY], // y축에 1자 선을 그립니다. [0, options.offsetY, canvasSize.horizontal, options.offsetY], // y축에 1자 선을 그립니다.
{ {
@ -718,132 +718,136 @@ export function useMode() {
lockScalingX: true, lockScalingX: true,
lockScalingY: true, lockScalingY: true,
name: 'guideLine', name: 'guideLine',
direction: 'horizontal',
}, },
) )
canvas?.add(line) canvas?.add(line)
canvas?.renderAll() canvas?.renderAll()
const newHorizontalLineArray = [...horiGuideLines, line] const newHorizontalLineArray = [...horiGuideLines]
newHorizontalLineArray.push(line)
setHoriGuideLines(newHorizontalLineArray) setHoriGuideLines(newHorizontalLineArray)
}, },
[canvas, horiGuideLines], [canvas, mode, horiGuideLines],
), ),
editMode: useCallback( editMode: (options) => {
(options) => { if (mode !== Mode.EDIT) {
let pointer = canvas?.getPointer(options.e) return
}
let pointer = canvas?.getPointer(options.e)
if (getInterSectPointByMouseLine()) { if (getInterSectPointByMouseLine()) {
pointer = getInterSectPointByMouseLine() pointer = getInterSectPointByMouseLine()
} }
const circle = new fabric.Circle({ const circle = new fabric.Circle({
radius: 5, radius: 5,
fill: 'transparent', // 원 안을 비웁니다. fill: 'transparent', // 원 안을 비웁니다.
stroke: 'red', // 원 테두리 색상을 검은색으로 설정합니다. stroke: 'red', // 원 테두리 색상을 검은색으로 설정합니다.
left: pointer.x, left: pointer.x,
top: pointer.y, top: pointer.y,
x: pointer.x, x: pointer.x,
y: pointer.y, y: pointer.y,
originX: 'center', originX: 'center',
originY: 'center', originY: 'center',
selectable: false, selectable: false,
}) })
if (!startPoint.current) { if (!startPoint.current) {
startPoint.current = circle startPoint.current = circle
pointCount.current = pointCount.current + 1 pointCount.current = pointCount.current + 1
} }
let prevEndPoint let prevEndPoint
setEndPoint((prev) => { setEndPoint((prev) => {
prevEndPoint = prev prevEndPoint = prev
return circle return circle
}) })
historyPoints.current.push(circle) historyPoints.current.push(circle)
points.current.push(circle) points.current.push(circle)
canvas?.add(circle) canvas?.add(circle)
if (points.current.length === 2) { if (points.current.length === 2) {
if (guideLineMode || guideDotMode) { if (guideLineMode || guideDotMode) {
const vector = { const vector = {
x: points.current[1].left - points.current[0].left, x: points.current[1].left - points.current[0].left,
y: points.current[1].top - points.current[0].top, y: points.current[1].top - points.current[0].top,
}
const slope = Math.abs(vector.y / vector.x) // 기울기 계산
let scaledVector
if (slope >= 1) {
// 기울기가 1 이상이면 x축 방향으로 그림
scaledVector = {
x: 0,
y: pointer.y - prevEndPoint?.top,
}
} else {
// 기울기가 1 미만이면 y축 방향으로 그림
scaledVector = {
x: pointer.x - prevEndPoint?.left,
y: 0,
}
}
const verticalLength = scaledVector.y
const horizontalLength = scaledVector.x
drawCircleAndLine(verticalLength, horizontalLength)
canvas?.renderAll()
return
} }
const length = Number(prompt('길이를 입력하세요:')) const slope = Math.abs(vector.y / vector.x) // 기울기 계산
// length 값이 숫자가 아닌 경우 let scaledVector
if (isNaN(length) || length === 0) {
//마지막 추가 된 points 제거합니다.
const lastPoint = historyPoints.current[historyPoints.current.length - 1] if (slope >= 1) {
// 기울기가 1 이상이면 x축 방향으로 그림
canvas?.remove(lastPoint) scaledVector = {
setEndPoint(prevEndPoint) x: 0,
historyPoints.current.pop() y: pointer.y - prevEndPoint?.top,
points.current.pop() }
return } else {
// 기울기가 1 미만이면 y축 방향으로 그림
scaledVector = {
x: pointer.x - prevEndPoint?.left,
y: 0,
}
} }
if (length) { const verticalLength = scaledVector.y
const vector = { const horizontalLength = scaledVector.x
x: points.current[1].left - points.current[0].left,
y: points.current[1].top - points.current[0].top,
}
const slope = Math.abs(vector.y / vector.x) // 기울기 계산
let scaledVector drawCircleAndLine(verticalLength, horizontalLength)
if (slope >= 1) { canvas?.renderAll()
// 기울기가 1 이상이면 x축 방향으로 그림 return
scaledVector = { }
x: 0, const length = Number(prompt('길이를 입력하세요:'))
y: vector.y >= 0 ? Number(length) : -Number(length),
}
} else {
// 기울기가 1 미만이면 y축 방향으로 그림
scaledVector = {
x: vector.x >= 0 ? Number(length) : -Number(length),
y: 0,
}
}
const verticalLength = scaledVector.y // length 값이 숫자가 아닌 경우
const horizontalLength = scaledVector.x if (isNaN(length) || length === 0) {
//마지막 추가 된 points 제거합니다.
drawCircleAndLine(verticalLength, horizontalLength) const lastPoint = historyPoints.current[historyPoints.current.length - 1]
}
canvas?.remove(lastPoint)
setEndPoint(prevEndPoint)
historyPoints.current.pop()
points.current.pop()
return
} }
canvas?.renderAll() if (length) {
}, const vector = {
[canvas], x: points.current[1].left - points.current[0].left,
), y: points.current[1].top - points.current[0].top,
textboxMode: useCallback((options) => { }
const slope = Math.abs(vector.y / vector.x) // 기울기 계산
let scaledVector
if (slope >= 1) {
// 기울기가 1 이상이면 x축 방향으로 그림
scaledVector = {
x: 0,
y: vector.y >= 0 ? Number(length) : -Number(length),
}
} else {
// 기울기가 1 미만이면 y축 방향으로 그림
scaledVector = {
x: vector.x >= 0 ? Number(length) : -Number(length),
y: 0,
}
}
const verticalLength = scaledVector.y
const horizontalLength = scaledVector.x
drawCircleAndLine(verticalLength, horizontalLength)
}
}
canvas?.renderAll()
},
textboxMode: (options) => {
if (mode !== Mode.TEXTBOX) return
if (canvas?.getActiveObject()?.type === 'textbox') return if (canvas?.getActiveObject()?.type === 'textbox') return
const pointer = canvas?.getPointer(options.e) const pointer = canvas?.getPointer(options.e)
@ -861,8 +865,9 @@ export function useMode() {
textbox?.on('editing:exited', function () { textbox?.on('editing:exited', function () {
changeMode(canvas, Mode.EDIT) changeMode(canvas, Mode.EDIT)
}) })
}, []), },
drawRectMode: useCallback((o) => { drawRectMode: (o) => {
if (mode !== Mode.DRAW_RECT) return
let rect, isDown, origX, origY let rect, isDown, origX, origY
isDown = true isDown = true
const pointer = canvas.getPointer(o.e) const pointer = canvas.getPointer(o.e)
@ -902,39 +907,37 @@ export function useMode() {
canvas.off('mouse:up') canvas.off('mouse:up')
setMode(Mode.DEFAULT) setMode(Mode.DEFAULT)
}) })
}, []), },
// 흡착점 추가 // 흡착점 추가
adsorptionPoint: useCallback( adsorptionPoint: (o) => {
(o) => { if (mode !== Mode.ADSORPTION_POINT) return
const pointer = canvas.getPointer(o.e) const pointer = canvas.getPointer(o.e)
let newX = pointer.x let newX = pointer.x
let newY = pointer.y let newY = pointer.y
if (getInterSectPointByMouseLine()) { if (getInterSectPointByMouseLine()) {
const interSectPoint = getInterSectPointByMouseLine() const interSectPoint = getInterSectPointByMouseLine()
newX = interSectPoint.x newX = interSectPoint.x
newY = interSectPoint.y newY = interSectPoint.y
} }
const circle = new fabric.Circle({ const circle = new fabric.Circle({
radius: 5, radius: 5,
fill: 'transparent', // 원 안을 비웁니다. fill: 'transparent', // 원 안을 비웁니다.
stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다. stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다.
left: newX, left: newX,
top: newY, top: newY,
originX: 'center', originX: 'center',
originY: 'center', originY: 'center',
x: newX - 5, x: newX - 5,
y: newY - 5, y: newY - 5,
selectable: false, selectable: false,
name: 'adsorptionPoint', name: 'adsorptionPoint',
}) })
canvas.add(circle) canvas.add(circle)
canvas.renderAll() canvas.renderAll()
}, },
[canvas],
),
} }
const getInterSectPointByMouseLine = () => { const getInterSectPointByMouseLine = () => {

View File

@ -95,3 +95,15 @@ export const currentObjectState = atom({
default: null, default: null,
dangerouslyAllowMutability: true, dangerouslyAllowMutability: true,
}) })
export const horiGuideLinesState = atom({
key: 'horiGuideLines',
default: [],
dangerouslyAllowMutability: true,
})
export const vertGuideLinesState = atom({
key: 'vertGuideLines',
default: [],
dangerouslyAllowMutability: true,
})