From 55068138ba5e6af534772643e8d5c99464a2f76e Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Wed, 21 Aug 2024 13:54:10 +0900 Subject: [PATCH 1/7] chore: Remove console.log statements from ThumbnailList component --- src/components/ui/ThumbnailLIst.jsx | 2 ++ src/hooks/useCanvas.js | 23 +++++++++-------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/components/ui/ThumbnailLIst.jsx b/src/components/ui/ThumbnailLIst.jsx index 04519262..26c40099 100644 --- a/src/components/ui/ThumbnailLIst.jsx +++ b/src/components/ui/ThumbnailLIst.jsx @@ -4,6 +4,8 @@ import { memo } from 'react' function ThumbnailList(props) { const { thumbnails } = props + console.log('ThumbnailList') + return ( <>
diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index 2740f669..fc3b678f 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -1,13 +1,6 @@ import { useEffect, useRef, useState } from 'react' import { fabric } from 'fabric' -import { - actionHandler, - anchorWrapper, - calculateIntersection, - distanceBetweenPoints, - polygonPositionHandler, - test, -} from '@/util/canvas-util' +import { actionHandler, anchorWrapper, calculateIntersection, distanceBetweenPoints, polygonPositionHandler, test } from '@/util/canvas-util' import { useRecoilState } from 'recoil' import { canvasSizeState, fontSizeState } from '@/store/canvasAtom' @@ -509,11 +502,13 @@ export function useCanvas(id) { * @param {string} title - 저장할 이미지 이름 */ const saveImage = async (title = 'canvas') => { - await writeImage(title, canvas?.toDataURL('image/png').replace('data:image/png;base64,', '')).then(res => { - console.log('success', res) - }).catch(err => { - console.log('err', err) - }) + await writeImage(title, canvas?.toDataURL('image/png').replace('data:image/png;base64,', '')) + .then((res) => { + console.log('success', res) + }) + .catch((err) => { + console.log('err', err) + }) } const handleFlip = () => { @@ -570,7 +565,7 @@ export function useCanvas(id) { const dataUrl = tempCanvas.toDataURL({ format: 'png' }) // Set the image as the background of the original canvas - fabric.Image.fromURL(dataUrl, function(img) { + fabric.Image.fromURL(dataUrl, function (img) { canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), { scaleX: canvas.width / img.width, scaleY: canvas.height / img.height, From 74604098023b1a6e8ab13298a008e37ab52a52b4 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Wed, 21 Aug 2024 17:19:32 +0900 Subject: [PATCH 2/7] =?UTF-8?q?refactor:=20error=20handling=20=EC=86=8C?= =?UTF-8?q?=EC=8A=A4=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 아직 미완성 --- src/app/[locale]/roof2/RoofSelect.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/[locale]/roof2/RoofSelect.jsx b/src/app/[locale]/roof2/RoofSelect.jsx index 25b9e04c..d759398b 100644 --- a/src/app/[locale]/roof2/RoofSelect.jsx +++ b/src/app/[locale]/roof2/RoofSelect.jsx @@ -19,9 +19,9 @@ export default function RoofSelect() { useEffect(() => { get({ url: '/api/roof-material/roof-material-infos' }).then((res) => { - if (res.length === 0) { - return - } + //TODO: error handling + if (!res) return + setRoofMaterials(res) }) }, []) From 7e68be16a1a495f02c2b9578b31fa43ae6fc0fee Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 21 Aug 2024 17:57:41 +0900 Subject: [PATCH 3/7] =?UTF-8?q?=EB=A7=88=EC=9A=B0=EC=8A=A4=20contextmenu?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 2 +- src/components/Roof2.jsx | 8 +++-- src/hooks/useCanvas.js | 10 ++----- src/hooks/useMode.js | 4 +-- src/util/context-util.js | 65 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 12 deletions(-) create mode 100644 src/util/context-util.js diff --git a/.env.development b/.env.development index 2f67a8f6..943a5d6b 100644 --- a/.env.development +++ b/.env.development @@ -1,6 +1,6 @@ NEXT_PUBLIC_TEST="테스트변수입니다. development" -NEXT_PUBLIC_API_SERVER_PATH="http://localhost:8080" +NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080" DATABASE_URL="sqlserver://mssql.devgrr.kr:1433;database=qcast;user=qcast;password=Qwertqaz12345;trustServerCertificate=true" diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 1acf612b..6d8f942d 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -1,5 +1,5 @@ import { useCanvas } from '@/hooks/useCanvas' -import { useEffect, useState } from 'react' +import { useEffect, useState, useRef } from 'react' import { Mode, useMode } from '@/hooks/useMode' import { Button } from '@nextui-org/react' import RangeSlider from './ui/RangeSlider' @@ -19,10 +19,13 @@ import { getCanvasState, insertCanvasState } from '@/lib/canvas' import { calculateIntersection } from '@/util/canvas-util' import { QPolygon } from '@/components/fabric/QPolygon' import ThumbnailList from './ui/ThumbnailLIst' +import CanvasWithContextMenu from '@/util/context-util' export default function Roof2() { const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage, addCanvas } = useCanvas('canvas') + const canvasRef = useRef(null) + //canvas 기본 사이즈 const [canvasSize, setCanvasSize] = useRecoilState(canvasSizeState) @@ -699,7 +702,8 @@ export default function Roof2() { )}
- + + {canvas !== undefined && }
) diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index fc3b678f..e5f5337f 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -64,15 +64,11 @@ export function useCanvas(id) { useEffect(() => { if (canvas) { initialize() - canvas?.on('object:added', onChange) - canvas?.on('object:added', addEventOnObject) - - canvas?.on('object:modified', onChange) - canvas?.on('object:removed', onChange) - canvas?.on('mouse:move', drawMouseLines) - canvas?.on('mouse:out', removeMouseLines) + removeEventOnCanvas() + addEventOnCanvas() } }, [canvas]) + const addEventOnCanvas = () => { canvas?.on('object:added', onChange) canvas?.on('object:modified', onChange) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 9ac623a1..bd86b460 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -277,7 +277,7 @@ export function useMode() { break case 'default': - canvas?.off('mouse:down') + // canvas?.off('mouse:down') break } } @@ -510,7 +510,7 @@ export function useMode() { setMode(mode) // mode변경 시 이전 이벤트 제거 setCanvas(canvas) - canvas?.off('mouse:down') + // canvas?.off('mouse:down') addEvent(mode) } diff --git a/src/util/context-util.js b/src/util/context-util.js new file mode 100644 index 00000000..0d14f1d9 --- /dev/null +++ b/src/util/context-util.js @@ -0,0 +1,65 @@ +import React, { useState, useEffect, forwardRef, useContext } from 'react' + +const CanvasWithContextMenu = forwardRef(({ canvasProps }, ref) => { + const [contextMenu, setContextMenu] = useState({ visible: false, x: 0, y: 0 }) + + useEffect(() => { + if (!ref.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) + } + }, [ref, contextMenu]) + + const handleMenuClick = (option) => { + alert(`option ${option} clicked`) + setContextMenu({ ...contextMenu, visible: false }) + } + + return ( + <> + {contextMenu.visible && ( +
+
    +
  • handleMenuClick(1)}> + Option 1 +
  • +
  • handleMenuClick(2)}> + Option 2 +
  • +
  • handleMenuClick(3)}> + Option 3 +
  • +
+
+ )} + + ) +}) + +export default CanvasWithContextMenu From 26a3f0753474b759f81251f6e255509093278d4b Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 21 Aug 2024 18:13:18 +0900 Subject: [PATCH 4/7] =?UTF-8?q?=EB=A7=88=EC=9A=B0=EC=8A=A4=20=ED=81=B4?= =?UTF-8?q?=EB=A6=AD=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index bd86b460..9ac623a1 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -277,7 +277,7 @@ export function useMode() { break case 'default': - // canvas?.off('mouse:down') + canvas?.off('mouse:down') break } } @@ -510,7 +510,7 @@ export function useMode() { setMode(mode) // mode변경 시 이전 이벤트 제거 setCanvas(canvas) - // canvas?.off('mouse:down') + canvas?.off('mouse:down') addEvent(mode) } From 813c75672754a5b9359e919a1a728e874d470d8f Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Wed, 21 Aug 2024 18:27:10 +0900 Subject: [PATCH 5/7] refactor: Add removeMouseLines --- src/components/Roof2.jsx | 2 +- src/hooks/useCanvas.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 6d8f942d..2ad0f8c8 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -629,7 +629,7 @@ export default function Roof2() { )} - {/*