선택된 object에 따라 오른쪽마우스 클릭 시 contextmenu 변경

This commit is contained in:
hyojun.choi 2024-08-26 10:22:49 +09:00
parent 39e8dc335e
commit 89f117c230
5 changed files with 183 additions and 5 deletions

View File

@ -11,6 +11,7 @@ import { useRecoilState, useRecoilValue } from 'recoil'
import { import {
canvasSizeState, canvasSizeState,
compassState, compassState,
currentObjectState,
fontSizeState, fontSizeState,
roofMaterialState, roofMaterialState,
roofState, roofState,
@ -27,6 +28,8 @@ import QContextMenu from './common/context-menu/QContextMenu'
import { modalContent, modalState } from '@/store/modalAtom' import { modalContent, modalState } from '@/store/modalAtom'
import SettingsModal from './SettingsModal' import SettingsModal from './SettingsModal'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import QPolygonContextMenu from '@/components/common/context-menu/QPolygonContextMenu'
import QLineContextMenu from '@/components/common/context-menu/QLineContextMenu'
export default function Roof2(props) { export default function Roof2(props) {
const { name, userId, email, isLoggedIn } = props const { name, userId, email, isLoggedIn } = props
@ -67,6 +70,7 @@ export default function Roof2(props) {
const [contents, setContent] = useRecoilState(modalContent) const [contents, setContent] = useRecoilState(modalContent)
const [scale, setScale] = useState(1) const [scale, setScale] = useState(1)
const currentObject = useRecoilValue(currentObjectState)
//canvas //canvas
const [thumbnails, setThumbnails] = useState([]) const [thumbnails, setThumbnails] = useState([])
@ -126,6 +130,7 @@ export default function Roof2(props) {
if (canvas) { if (canvas) {
const line = new QLine([50, 50, 200, 50], { const line = new QLine([50, 50, 200, 50], {
stroke: 'black', stroke: 'black',
selectable: true,
strokeWidth: 2, strokeWidth: 2,
fontSize: fontSize, fontSize: fontSize,
}) })
@ -758,7 +763,13 @@ export default function Roof2(props) {
<ThumbnailList {...thumbnailProps} /> <ThumbnailList {...thumbnailProps} />
<div className="flex justify-start my-8 mx-2 w-full"> <div className="flex justify-start my-8 mx-2 w-full">
<canvas ref={canvasRef} id="canvas" style={{ border: '1px solid black' }} /> <canvas ref={canvasRef} id="canvas" style={{ border: '1px solid black' }} />
{canvas !== undefined && <QContextMenu contextRef={canvasRef} canvasProps={canvas} />} {!canvas ? null : currentObject?.type === 'QPolygon' ? (
<QPolygonContextMenu contextRef={canvasRef} canvasProps={canvas} />
) : currentObject?.type === 'QLine' ? (
<QLineContextMenu contextRef={canvasRef} canvasProps={canvas} />
) : (
<QContextMenu contextRef={canvasRef} canvasProps={canvas} />
)}
</div> </div>
</> </>
) )

View File

@ -0,0 +1,71 @@
'use client'
import { useEffect, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
export default function QLineContextMenu(props) {
const { contextRef, canvasProps } = props
// const children = useRecoilValue(modalContent)
const [contextMenu, setContextMenu] = useState({ visible: false, x: 0, y: 0 })
useEffect(() => {
if (!contextRef.current) return
const handleContextMenu = (e) => {
e.preventDefault() // contextmenu
setContextMenu({ visible: true, x: e.pageX, y: e.pageY })
canvasProps.upperCanvasEl.removeEventListener('contextmenu', handleContextMenu) //
}
const handleClick = (e) => {
e.preventDefault()
setContextMenu({ ...contextMenu, visible: false })
}
const handleOutsideClick = (e) => {
e.preventDefault()
if (contextMenu.visible && !ref.current.contains(e.target)) {
setContextMenu({ ...contextMenu, visible: false })
}
}
// Prevent the default context menu from appearing on the canvas
canvasProps.upperCanvasEl.addEventListener('contextmenu', handleContextMenu)
document.addEventListener('click', handleClick)
document.addEventListener('click', handleOutsideClick)
return () => {
// canvasProps.upperCanvasEl.removeEventListener('contextmenu', handleContextMenu)
document.removeEventListener('click', handleClick)
document.removeEventListener('click', handleOutsideClick)
}
}, [contextRef, contextMenu])
const handleMenuClick = (option) => {
alert(`option ${option} clicked`)
setContextMenu({ ...contextMenu, visible: false })
}
return (
<>
{contextMenu.visible && (
<div style={{ position: 'absolute', top: contextMenu.y, left: contextMenu.x, zIndex: 2000 }}>
<ul style={{ listStyle: 'none', margin: 0, padding: '5px' }}>
<li style={{ padding: '8px 12px', cursor: 'pointer' }} onClick={() => handleMenuClick(1)}>
line
</li>
<li style={{ padding: '8px 12px', cursor: 'pointer' }} onClick={() => handleMenuClick(1)}>
Option 1
</li>
<li style={{ padding: '8px 12px', cursor: 'pointer' }} onClick={() => handleMenuClick(2)}>
Option 2
</li>
<li style={{ padding: '8px 12px', cursor: 'pointer' }} onClick={() => handleMenuClick(3)}>
Option 3
</li>
</ul>
</div>
)}
</>
)
}

View File

@ -0,0 +1,71 @@
'use client'
import { useEffect, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
export default function QPolygonContextMenu(props) {
const { contextRef, canvasProps } = props
// const children = useRecoilValue(modalContent)
const [contextMenu, setContextMenu] = useState({ visible: false, x: 0, y: 0 })
useEffect(() => {
if (!contextRef.current) return
const handleContextMenu = (e) => {
e.preventDefault() // contextmenu
setContextMenu({ visible: true, x: e.pageX, y: e.pageY })
canvasProps.upperCanvasEl.removeEventListener('contextmenu', handleContextMenu) //
}
const handleClick = (e) => {
e.preventDefault()
setContextMenu({ ...contextMenu, visible: false })
}
const handleOutsideClick = (e) => {
e.preventDefault()
if (contextMenu.visible && !ref.current.contains(e.target)) {
setContextMenu({ ...contextMenu, visible: false })
}
}
// Prevent the default context menu from appearing on the canvas
canvasProps.upperCanvasEl.addEventListener('contextmenu', handleContextMenu)
document.addEventListener('click', handleClick)
document.addEventListener('click', handleOutsideClick)
return () => {
// canvasProps.upperCanvasEl.removeEventListener('contextmenu', handleContextMenu)
document.removeEventListener('click', handleClick)
document.removeEventListener('click', handleOutsideClick)
}
}, [contextRef, contextMenu])
const handleMenuClick = (option) => {
alert(`option ${option} clicked`)
setContextMenu({ ...contextMenu, visible: false })
}
return (
<>
{contextMenu.visible && (
<div style={{ position: 'absolute', top: contextMenu.y, left: contextMenu.x, zIndex: 2000 }}>
<ul style={{ listStyle: 'none', margin: 0, padding: '5px' }}>
<li style={{ padding: '8px 12px', cursor: 'pointer' }} onClick={() => handleMenuClick(1)}>
polygon
</li>
<li style={{ padding: '8px 12px', cursor: 'pointer' }} onClick={() => handleMenuClick(1)}>
Option 1
</li>
<li style={{ padding: '8px 12px', cursor: 'pointer' }} onClick={() => handleMenuClick(2)}>
Option 2
</li>
<li style={{ padding: '8px 12px', cursor: 'pointer' }} onClick={() => handleMenuClick(3)}>
Option 3
</li>
</ul>
</div>
)}
</>
)
}

View File

@ -1,11 +1,12 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { fabric } from 'fabric' import { fabric } from 'fabric'
import { useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
import { canvasSizeState, modeState } from '@/store/canvasAtom' import { canvasSizeState, currentObjectState, modeState } from '@/store/canvasAtom'
// 캔버스에 필요한 이벤트 // 캔버스에 필요한 이벤트
export function useCanvasEvent() { export function useCanvasEvent() {
const [canvas, setCanvasForEvent] = useState(null) const [canvas, setCanvasForEvent] = useState(null)
const [currentObject, setCurrentObject] = useRecoilState(currentObjectState)
const canvasSize = useRecoilValue(canvasSizeState) const canvasSize = useRecoilValue(canvasSizeState)
// 기본적인 이벤트 필요시 추가 // 기본적인 이벤트 필요시 추가
@ -15,11 +16,28 @@ export function useCanvasEvent() {
canvas?.on('object:added', addEventOnObject) canvas?.on('object:added', addEventOnObject)
canvas?.on('object:modified', onChange) canvas?.on('object:modified', onChange)
canvas?.on('object:removed', onChange) canvas?.on('object:removed', onChange)
canvas?.on('selection:cleared', selectionEvent.cleared)
canvas?.on('selection:created', selectionEvent.created)
canvas?.on('selection:updated', selectionEvent.updated)
canvas?.on('object:added', () => { canvas?.on('object:added', () => {
document.addEventListener('keydown', handleKeyDown) document.addEventListener('keydown', handleKeyDown)
}) })
} }
const selectionEvent = {
created: (e) => {
const target = e.selected[0]
setCurrentObject(target)
},
cleared: (e) => {
setCurrentObject(null)
},
updated: (e) => {
const target = e.selected[0]
setCurrentObject(target)
},
}
const onChange = (e) => { const onChange = (e) => {
const target = e.target const target = e.target
if (target) { if (target) {
@ -32,8 +50,9 @@ export function useCanvasEvent() {
canvas?.off('object:modified') canvas?.off('object:modified')
canvas?.off('object:removed') canvas?.off('object:removed')
canvas?.off('object:added') canvas?.off('object:added')
canvas?.off('mouse:move') canvas?.off('selection:cleared')
canvas?.off('mouse:down') canvas?.off('selection:created')
canvas?.off('selection:updated')
} }
const addEventOnObject = (e) => { const addEventOnObject = (e) => {

View File

@ -94,3 +94,9 @@ export const guideLineState = atom({
default: {}, default: {},
dangerouslyAllowMutability: true, dangerouslyAllowMutability: true,
}) })
export const currentObjectState = atom({
key: 'currentObject',
default: null,
dangerouslyAllowMutability: true,
})