136 lines
3.9 KiB
JavaScript
136 lines
3.9 KiB
JavaScript
import { useEffect, useRef } from 'react'
|
|
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
|
|
import { canvasState, canvasZoomState, currentMenuState } from '@/store/canvasAtom'
|
|
import { fabric } from 'fabric'
|
|
|
|
export function useEvent() {
|
|
const canvas = useRecoilValue(canvasState)
|
|
const currentMenu = useRecoilValue(currentMenuState)
|
|
const keyboardEventListeners = useRef([])
|
|
const mouseEventListeners = useRef([])
|
|
const setCanvasZoom = useSetRecoilState(canvasZoomState)
|
|
|
|
useEffect(() => {
|
|
if (!canvas) {
|
|
return
|
|
}
|
|
removeAllMouseEventListeners()
|
|
removeAllDocumentEventListeners()
|
|
addDefaultEvent()
|
|
}, [currentMenu, canvas])
|
|
|
|
const addDefaultEvent = () => {
|
|
//default Event 추가
|
|
addCanvasMouseEventListener('mouse:move', defaultMouseMoveEvent)
|
|
addCanvasMouseEventListener('mouse:out', defaultMouseOutEvent)
|
|
addCanvasMouseEventListener('mouse:wheel', wheelEvent)
|
|
addDocumentEventListener('keydown', document, defaultKeyboardEvent)
|
|
}
|
|
|
|
const wheelEvent = (opt) => {
|
|
const delta = opt.e.deltaY // 휠 이동 값 (양수면 축소, 음수면 확대)
|
|
let zoom = canvas.getZoom() // 현재 줌 값
|
|
|
|
zoom += delta > 0 ? -0.1 : 0.1
|
|
|
|
// 줌 값 제한 (최소 0.5배, 최대 5배)
|
|
if (zoom > 5) zoom = 5
|
|
if (zoom < 0.5) zoom = 0.5
|
|
|
|
setCanvasZoom((zoom * 100).toFixed(0))
|
|
|
|
// 마우스 위치 기준으로 확대/축소
|
|
canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom)
|
|
|
|
// 이벤트의 기본 동작 방지 (스크롤 방지)
|
|
opt.e.preventDefault()
|
|
opt.e.stopPropagation()
|
|
}
|
|
|
|
const defaultMouseOutEvent = (e) => {
|
|
removeMouseLine()
|
|
}
|
|
|
|
const defaultMouseMoveEvent = (e) => {
|
|
removeMouseLine()
|
|
// 가로선
|
|
const pointer = canvas.getPointer(e.e)
|
|
const horizontalLine = new fabric.Line([0, pointer.y, 2 * canvas.width, pointer.y], {
|
|
stroke: 'red',
|
|
strokeWidth: 1,
|
|
selectable: false,
|
|
name: 'mouseLine',
|
|
})
|
|
|
|
// 세로선
|
|
const verticalLine = new fabric.Line([pointer.x, 0, pointer.x, 2 * canvas.height], {
|
|
stroke: 'red',
|
|
strokeWidth: 1,
|
|
selectable: false,
|
|
name: 'mouseLine',
|
|
})
|
|
|
|
// 선들을 캔버스에 추가합니다.
|
|
canvas?.add(horizontalLine, verticalLine)
|
|
|
|
// 캔버스를 다시 그립니다.
|
|
canvas?.renderAll()
|
|
}
|
|
|
|
const removeMouseLine = () => {
|
|
// 캔버스에서 마우스 선을 찾아 제거합니다.
|
|
canvas
|
|
?.getObjects()
|
|
.filter((obj) => obj.name === 'mouseLine')
|
|
.forEach((line) => {
|
|
canvas?.remove(line)
|
|
})
|
|
}
|
|
|
|
const defaultKeyboardEvent = (e) => {
|
|
if (e.key === 'Escape') {
|
|
console.log('defaultKeyboardEvent')
|
|
}
|
|
}
|
|
|
|
const addCanvasMouseEventListener = (eventType, handler) => {
|
|
canvas.on(eventType, handler)
|
|
mouseEventListeners.current.push({ eventType, handler })
|
|
}
|
|
|
|
const removeAllMouseEventListeners = () => {
|
|
mouseEventListeners.current.forEach(({ eventType, handler }) => {
|
|
canvas.off(eventType, handler)
|
|
})
|
|
mouseEventListeners.current.length = 0 // 배열 초기화
|
|
}
|
|
|
|
/**
|
|
* document 이벤트의 경우 이 함수를 통해서만 등록
|
|
* @param eventType
|
|
* @param element
|
|
* @param handler
|
|
*/
|
|
const addDocumentEventListener = (eventType, element, handler) => {
|
|
element.addEventListener(eventType, handler)
|
|
keyboardEventListeners.current.push({ eventType, element, handler })
|
|
}
|
|
|
|
/**
|
|
* document에 등록되는 event 제거
|
|
*/
|
|
const removeAllDocumentEventListeners = () => {
|
|
keyboardEventListeners.current.forEach(({ eventType, element, handler }) => {
|
|
element.removeEventListener(eventType, handler)
|
|
})
|
|
keyboardEventListeners.current.length = 0 // 배열 초기화
|
|
}
|
|
|
|
return {
|
|
addDocumentEventListener,
|
|
addCanvasMouseEventListener,
|
|
removeAllMouseEventListeners,
|
|
removeAllDocumentEventListeners,
|
|
}
|
|
}
|