흡착점 추가
This commit is contained in:
parent
c6801960b5
commit
1c2d3b7968
@ -5,7 +5,13 @@ import WithDraggable from '@/components/common/draggable/withDraggable'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
import { canvasState, verticalHorizontalModeState } from '@/store/canvasAtom'
|
||||
import {
|
||||
adsorptionPointAddModeState,
|
||||
adsorptionPointModeState,
|
||||
canvasHistoryState,
|
||||
canvasState,
|
||||
verticalHorizontalModeState,
|
||||
} from '@/store/canvasAtom'
|
||||
import {
|
||||
OUTER_LINE_TYPE,
|
||||
outerLineAngle1State,
|
||||
@ -25,11 +31,18 @@ import { onlyNumberInputChange, onlyNumberWithDotInputChange } from '@/util/inpu
|
||||
export default function OuterLineWall(props) {
|
||||
const { setShowOutlineModal } = props
|
||||
const { getMessage } = useMessage()
|
||||
const { addCanvasMouseEventListener, addDocumentEventListener, removeAllMouseEventListeners, removeAllDocumentEventListeners, removeMouseEvent } =
|
||||
useEvent()
|
||||
const {
|
||||
addCanvasMouseEventListener,
|
||||
addDocumentEventListener,
|
||||
removeAllMouseEventListeners,
|
||||
removeAllDocumentEventListeners,
|
||||
removeMouseEvent,
|
||||
getIntersectMousePoint,
|
||||
} = useEvent()
|
||||
const { addLine, removeLine } = useLine()
|
||||
const { addPolygonByLines } = usePolygon()
|
||||
const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState)
|
||||
const adsorptionPointAddMode = useRecoilValue(adsorptionPointAddModeState)
|
||||
|
||||
const length1Ref = useRef(null)
|
||||
const length2Ref = useRef(null)
|
||||
@ -50,13 +63,16 @@ export default function OuterLineWall(props) {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
|
||||
useEffect(() => {
|
||||
if (adsorptionPointAddMode) {
|
||||
return
|
||||
}
|
||||
removeMouseEvent('mouse:down', mouseDown)
|
||||
addCanvasMouseEventListener('mouse:down', mouseDown)
|
||||
clear()
|
||||
return () => {
|
||||
removeAllMouseEventListeners()
|
||||
}
|
||||
}, [verticalHorizontalMode, points])
|
||||
}, [verticalHorizontalMode, points, adsorptionPointAddMode])
|
||||
|
||||
useEffect(() => {
|
||||
arrow1Ref.current = arrow1
|
||||
@ -83,7 +99,8 @@ export default function OuterLineWall(props) {
|
||||
}
|
||||
|
||||
const mouseDown = (e) => {
|
||||
const pointer = canvas.getPointer(e.e)
|
||||
let pointer = getIntersectMousePoint(e)
|
||||
|
||||
if (points.length === 0) {
|
||||
setPoints((prev) => [...prev, pointer])
|
||||
} else {
|
||||
@ -328,6 +345,12 @@ export default function OuterLineWall(props) {
|
||||
if (points.length === 0) {
|
||||
return
|
||||
}
|
||||
// 포커스가 length1에 있지 않으면 length1에 포커스를 줌
|
||||
const activeElem = document.activeElement
|
||||
if (activeElem !== length1Ref.current) {
|
||||
length1Ref.current.focus()
|
||||
}
|
||||
|
||||
const key = e.key
|
||||
|
||||
if (!length1Ref.current) {
|
||||
@ -389,6 +412,9 @@ export default function OuterLineWall(props) {
|
||||
const key = e.key
|
||||
|
||||
const activeElem = document.activeElement
|
||||
if (activeElem !== length1Ref.current && activeElem !== length2Ref.current) {
|
||||
length1Ref.current.focus()
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case 'Down': // IE/Edge에서 사용되는 값
|
||||
|
||||
@ -4,6 +4,7 @@ import { useMessage } from '@/hooks/useMessage'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { toastUp } from '@/hooks/useToast'
|
||||
import { adsorptionPointAddModeState } from '@/store/canvasAtom'
|
||||
|
||||
export default function FirstOption() {
|
||||
const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요
|
||||
|
||||
@ -2,10 +2,12 @@ import React from 'react'
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { settingModalGridOptionsState } from '@/store/settingAtom'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { adsorptionPointAddModeState } from '@/store/canvasAtom'
|
||||
|
||||
export default function GridOption(props) {
|
||||
const { setShowDotLineGridModal } = props
|
||||
const [gridOptions, setGridOptions] = useRecoilState(settingModalGridOptionsState)
|
||||
const [adsorptionPointAddMode, setAdsorptionPointAddMode] = useRecoilState(adsorptionPointAddModeState)
|
||||
const { getMessage } = useMessage()
|
||||
|
||||
const onClickOption = (option) => {
|
||||
@ -16,7 +18,12 @@ export default function GridOption(props) {
|
||||
// 점.선 그리드
|
||||
setShowDotLineGridModal(true)
|
||||
}
|
||||
|
||||
if (option.name === 'modal.canvas.setting.grid.absorption.add') {
|
||||
setAdsorptionPointAddMode(!adsorptionPointAddMode)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="modal-check-btn-wrap">
|
||||
|
||||
@ -1,14 +1,18 @@
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { useRecoilState, useSetRecoilState } from 'recoil'
|
||||
import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { toastUp } from '@/hooks/useToast'
|
||||
import { adsorptionPointModeState, adsorptionRangeState } from '@/store/canvasAtom'
|
||||
|
||||
export default function SecondOption() {
|
||||
const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요
|
||||
const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState)
|
||||
const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState)
|
||||
const [adsorptionPointMode, setAdsorptionPointMode] = useRecoilState(adsorptionPointModeState)
|
||||
const setAdsorptionRange = useSetRecoilState(adsorptionRangeState)
|
||||
|
||||
const { option1, option2 } = settingModalFirstOptions
|
||||
const { option3, option4 } = settingModalSecondOptions
|
||||
const { getMessage } = useMessage()
|
||||
@ -106,6 +110,7 @@ export default function SecondOption() {
|
||||
// HTTP POST 요청 보내기
|
||||
await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }).then((res) => {
|
||||
toastUp({ message: getMessage(res.returnMessage), type: 'success' })
|
||||
setAdsorptionRange(option.range)
|
||||
})
|
||||
} catch (error) {
|
||||
toastUp({ message: getMessage(res.returnMessage), type: 'error' })
|
||||
@ -142,9 +147,14 @@ export default function SecondOption() {
|
||||
<button className="arr-btn">
|
||||
<span>{getMessage('modal.canvas.setting.font.plan.absorption.plan.size.setting')}</span>
|
||||
</button>
|
||||
<button className="adsorption-point act">
|
||||
<button
|
||||
className="adsorption-point act"
|
||||
onClick={(e) => {
|
||||
setAdsorptionPointMode(!adsorptionPointMode)
|
||||
}}
|
||||
>
|
||||
<span>{getMessage('modal.canvas.setting.font.plan.absorption.point')}</span>
|
||||
<i>ON</i>
|
||||
<i>{adsorptionPointMode ? 'ON' : 'OFF'}</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -490,6 +490,34 @@ export function useCanvas(id) {
|
||||
canvas.clear()
|
||||
}
|
||||
|
||||
const getCurrentCanvas = () => {
|
||||
return canvas.toJSON([
|
||||
'selectable',
|
||||
'name',
|
||||
'parentId',
|
||||
'id',
|
||||
'length',
|
||||
'idx',
|
||||
'direction',
|
||||
'lines',
|
||||
'points',
|
||||
'lockMovementX',
|
||||
'lockMovementY',
|
||||
'lockRotation',
|
||||
'lockScalingX',
|
||||
'lockScalingY',
|
||||
'opacity',
|
||||
'cells',
|
||||
'maxX',
|
||||
'maxY',
|
||||
'minX',
|
||||
'minY',
|
||||
'x',
|
||||
'y',
|
||||
'stickeyPoint',
|
||||
])
|
||||
}
|
||||
|
||||
return {
|
||||
canvas,
|
||||
addShape,
|
||||
|
||||
@ -1,7 +1,15 @@
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { canvasState, canvasZoomState, currentMenuState } from '@/store/canvasAtom'
|
||||
import {
|
||||
adsorptionPointAddModeState,
|
||||
adsorptionPointModeState,
|
||||
adsorptionRangeState,
|
||||
canvasState,
|
||||
canvasZoomState,
|
||||
currentMenuState,
|
||||
} from '@/store/canvasAtom'
|
||||
import { fabric } from 'fabric'
|
||||
import { calculateIntersection, distanceBetweenPoints } from '@/util/canvas-util'
|
||||
|
||||
export function useEvent() {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
@ -9,6 +17,9 @@ export function useEvent() {
|
||||
const keyboardEventListeners = useRef([])
|
||||
const mouseEventListeners = useRef([])
|
||||
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
|
||||
const adsorptionPointAddMode = useRecoilValue(adsorptionPointAddModeState)
|
||||
const adsorptionPointMode = useRecoilValue(adsorptionPointModeState)
|
||||
const adsorptionRange = useRecoilValue(adsorptionRangeState)
|
||||
|
||||
useEffect(() => {
|
||||
if (!canvas) {
|
||||
@ -24,14 +35,42 @@ export function useEvent() {
|
||||
canvas?.on('mouse:wheel', wheelEvent)
|
||||
|
||||
addDefaultEvent()
|
||||
}, [currentMenu, canvas])
|
||||
}, [currentMenu, canvas, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange])
|
||||
|
||||
const addDefaultEvent = () => {
|
||||
//default Event 추가
|
||||
addCanvasMouseEventListener('mouse:move', defaultMouseMoveEvent)
|
||||
addCanvasMouseEventListener('mouse:out', defaultMouseOutEvent)
|
||||
|
||||
if (adsorptionPointAddMode) {
|
||||
addCanvasMouseEventListener('mouse:down', adsorptionPointAddModeStateEvent)
|
||||
}
|
||||
addDocumentEventListener('keydown', document, defaultKeyboardEvent)
|
||||
addDocumentEventListener('contextmenu', document, defaultContextMenuEvent)
|
||||
}
|
||||
|
||||
const defaultContextMenuEvent = (e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}
|
||||
|
||||
const adsorptionPointAddModeStateEvent = (opt) => {
|
||||
//흡착점 모드일 경우
|
||||
let pointer = getIntersectMousePoint(opt)
|
||||
|
||||
const adsorptionPoint = new fabric.Circle({
|
||||
radius: 3,
|
||||
fill: 'red',
|
||||
left: pointer.x - 3,
|
||||
top: pointer.y - 3,
|
||||
x: pointer.x,
|
||||
y: pointer.y,
|
||||
selectable: false,
|
||||
name: 'adsorptionPoint',
|
||||
})
|
||||
|
||||
canvas.add(adsorptionPoint)
|
||||
|
||||
canvas.renderAll()
|
||||
}
|
||||
|
||||
const wheelEvent = (opt) => {
|
||||
@ -62,7 +101,28 @@ export function useEvent() {
|
||||
removeMouseLine()
|
||||
// 가로선
|
||||
const pointer = canvas.getPointer(e.e)
|
||||
const horizontalLine = new fabric.Line([-1 * canvas.width, pointer.y, 2 * canvas.width, pointer.y], {
|
||||
|
||||
const adsorptionPoints = getAdsorptionPoints()
|
||||
|
||||
let arrivalPoint = { x: pointer.x, y: pointer.y }
|
||||
|
||||
if (adsorptionPointMode) {
|
||||
// pointer와 adsorptionPoints의 거리를 계산하여 가장 가까운 점을 찾는다.
|
||||
let minDistance = adsorptionRange
|
||||
let adsorptionPoint = null
|
||||
adsorptionPoints.forEach((point) => {
|
||||
const distance = distanceBetweenPoints(pointer, point)
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance
|
||||
adsorptionPoint = point
|
||||
}
|
||||
})
|
||||
if (adsorptionPoint) {
|
||||
arrivalPoint = { ...adsorptionPoint }
|
||||
}
|
||||
}
|
||||
|
||||
const horizontalLine = new fabric.Line([-1 * canvas.width, arrivalPoint.y, 2 * canvas.width, arrivalPoint.y], {
|
||||
stroke: 'red',
|
||||
strokeWidth: 1,
|
||||
selectable: false,
|
||||
@ -70,7 +130,7 @@ export function useEvent() {
|
||||
})
|
||||
|
||||
// 세로선
|
||||
const verticalLine = new fabric.Line([pointer.x, -1 * canvas.height, pointer.x, 2 * canvas.height], {
|
||||
const verticalLine = new fabric.Line([arrivalPoint.x, -1 * canvas.height, arrivalPoint.x, 2 * canvas.height], {
|
||||
stroke: 'red',
|
||||
strokeWidth: 1,
|
||||
selectable: false,
|
||||
@ -143,11 +203,28 @@ export function useEvent() {
|
||||
})
|
||||
}
|
||||
|
||||
const getAdsorptionPoints = () => {
|
||||
return canvas.getObjects().filter((obj) => obj.visible && obj.name === 'adsorptionPoint')
|
||||
}
|
||||
|
||||
//가로선, 세로선의 교차점을 return
|
||||
const getIntersectMousePoint = (e) => {
|
||||
let pointer = canvas.getPointer(e.e)
|
||||
const mouseLines = canvas.getObjects().filter((obj) => obj.name === 'mouseLine')
|
||||
|
||||
if (mouseLines.length < 2) {
|
||||
return pointer
|
||||
}
|
||||
|
||||
return calculateIntersection(mouseLines[0], mouseLines[1]) ?? pointer
|
||||
}
|
||||
|
||||
return {
|
||||
addDocumentEventListener,
|
||||
addCanvasMouseEventListener,
|
||||
removeAllMouseEventListeners,
|
||||
removeAllDocumentEventListeners,
|
||||
removeMouseEvent,
|
||||
getIntersectMousePoint,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { atom } from 'recoil'
|
||||
import { atom, selector } from 'recoil'
|
||||
import { MENU } from '@/common/common'
|
||||
|
||||
export const canvasState = atom({
|
||||
@ -201,3 +201,20 @@ export const verticalHorizontalModeState = atom({
|
||||
key: 'verticalHorizontalMode',
|
||||
default: true,
|
||||
})
|
||||
|
||||
// 흡착점 모드
|
||||
export const adsorptionPointModeState = atom({
|
||||
key: 'adsorptionPointModeState',
|
||||
default: false,
|
||||
})
|
||||
// 흡착점 추가모드
|
||||
export const adsorptionPointAddModeState = atom({
|
||||
key: 'adsorptionPointAddModeState',
|
||||
default: false,
|
||||
})
|
||||
|
||||
// 흡착점 범위
|
||||
export const adsorptionRangeState = atom({
|
||||
key: 'adsorptionRangeState',
|
||||
default: 50,
|
||||
})
|
||||
|
||||
@ -40,10 +40,10 @@ export const settingModalSecondOptionsState = atom({
|
||||
{ id: 4, name: 'modal.canvas.setting.font.plan.edit.circuit.num' },
|
||||
],
|
||||
option4: [
|
||||
{ id: 1, column: 'adsorpRangeSmall', name: 'modal.canvas.setting.font.plan.absorption.small', selected: true },
|
||||
{ id: 2, column: 'adsorpRangeSmallSemi', name: 'modal.canvas.setting.font.plan.absorption.small.semi', selected: false },
|
||||
{ id: 3, column: 'adsorpRangeMedium', name: 'modal.canvas.setting.font.plan.absorption.medium', selected: false },
|
||||
{ id: 4, column: 'adsorpRangeLarge', name: 'modal.canvas.setting.font.plan.absorption.large', selected: false },
|
||||
{ id: 1, column: 'adsorpRangeSmall', name: 'modal.canvas.setting.font.plan.absorption.small', selected: true, range: 10 },
|
||||
{ id: 2, column: 'adsorpRangeSmallSemi', name: 'modal.canvas.setting.font.plan.absorption.small.semi', selected: false, range: 30 },
|
||||
{ id: 3, column: 'adsorpRangeMedium', name: 'modal.canvas.setting.font.plan.absorption.medium', selected: false, range: 50 },
|
||||
{ id: 4, column: 'adsorpRangeLarge', name: 'modal.canvas.setting.font.plan.absorption.large', selected: false, range: 80 },
|
||||
],
|
||||
},
|
||||
dangerouslyAllowMutability: true,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user