From 89f117c230c3efc91c4f49ab0307f80a80f6c64a Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 26 Aug 2024 10:22:49 +0900 Subject: [PATCH 1/6] =?UTF-8?q?=EC=84=A0=ED=83=9D=EB=90=9C=20object?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EC=98=A4=EB=A5=B8=EC=AA=BD?= =?UTF-8?q?=EB=A7=88=EC=9A=B0=EC=8A=A4=20=ED=81=B4=EB=A6=AD=20=EC=8B=9C=20?= =?UTF-8?q?contextmenu=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 13 +++- .../common/context-menu/QLineContextMenu.jsx | 71 +++++++++++++++++++ .../context-menu/QPolygonContextMenu.jsx | 71 +++++++++++++++++++ src/hooks/useCanvasEvent.js | 27 +++++-- src/store/canvasAtom.js | 6 ++ 5 files changed, 183 insertions(+), 5 deletions(-) create mode 100644 src/components/common/context-menu/QLineContextMenu.jsx create mode 100644 src/components/common/context-menu/QPolygonContextMenu.jsx diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 7467a634..2cfd6fae 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -11,6 +11,7 @@ import { useRecoilState, useRecoilValue } from 'recoil' import { canvasSizeState, compassState, + currentObjectState, fontSizeState, roofMaterialState, roofState, @@ -27,6 +28,8 @@ import QContextMenu from './common/context-menu/QContextMenu' import { modalContent, modalState } from '@/store/modalAtom' import SettingsModal from './SettingsModal' 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) { const { name, userId, email, isLoggedIn } = props @@ -67,6 +70,7 @@ export default function Roof2(props) { const [contents, setContent] = useRecoilState(modalContent) const [scale, setScale] = useState(1) + const currentObject = useRecoilValue(currentObjectState) //canvas 썸네일 const [thumbnails, setThumbnails] = useState([]) @@ -126,6 +130,7 @@ export default function Roof2(props) { if (canvas) { const line = new QLine([50, 50, 200, 50], { stroke: 'black', + selectable: true, strokeWidth: 2, fontSize: fontSize, }) @@ -758,7 +763,13 @@ export default function Roof2(props) {
- {canvas !== undefined && } + {!canvas ? null : currentObject?.type === 'QPolygon' ? ( + + ) : currentObject?.type === 'QLine' ? ( + + ) : ( + + )}
) diff --git a/src/components/common/context-menu/QLineContextMenu.jsx b/src/components/common/context-menu/QLineContextMenu.jsx new file mode 100644 index 00000000..058c3b95 --- /dev/null +++ b/src/components/common/context-menu/QLineContextMenu.jsx @@ -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 && ( +
+
    +
  • handleMenuClick(1)}> + line +
  • +
  • handleMenuClick(1)}> + Option 1 +
  • +
  • handleMenuClick(2)}> + Option 2 +
  • +
  • handleMenuClick(3)}> + Option 3 +
  • +
+
+ )} + + ) +} diff --git a/src/components/common/context-menu/QPolygonContextMenu.jsx b/src/components/common/context-menu/QPolygonContextMenu.jsx new file mode 100644 index 00000000..b3246165 --- /dev/null +++ b/src/components/common/context-menu/QPolygonContextMenu.jsx @@ -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 && ( +
+
    +
  • handleMenuClick(1)}> + polygon +
  • +
  • handleMenuClick(1)}> + Option 1 +
  • +
  • handleMenuClick(2)}> + Option 2 +
  • +
  • handleMenuClick(3)}> + Option 3 +
  • +
+
+ )} + + ) +} diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index 1947708f..ea5256e6 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -1,11 +1,12 @@ import { useEffect, useState } from 'react' import { fabric } from 'fabric' -import { useRecoilValue } from 'recoil' -import { canvasSizeState, modeState } from '@/store/canvasAtom' +import { useRecoilState, useRecoilValue } from 'recoil' +import { canvasSizeState, currentObjectState, modeState } from '@/store/canvasAtom' // 캔버스에 필요한 이벤트 export function useCanvasEvent() { const [canvas, setCanvasForEvent] = useState(null) + const [currentObject, setCurrentObject] = useRecoilState(currentObjectState) const canvasSize = useRecoilValue(canvasSizeState) // 기본적인 이벤트 필요시 추가 @@ -15,11 +16,28 @@ export function useCanvasEvent() { canvas?.on('object:added', addEventOnObject) canvas?.on('object:modified', 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', () => { 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 target = e.target if (target) { @@ -32,8 +50,9 @@ export function useCanvasEvent() { canvas?.off('object:modified') canvas?.off('object:removed') canvas?.off('object:added') - canvas?.off('mouse:move') - canvas?.off('mouse:down') + canvas?.off('selection:cleared') + canvas?.off('selection:created') + canvas?.off('selection:updated') } const addEventOnObject = (e) => { diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index 062698c0..fafe26a1 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -94,3 +94,9 @@ export const guideLineState = atom({ default: {}, dangerouslyAllowMutability: true, }) + +export const currentObjectState = atom({ + key: 'currentObject', + default: null, + dangerouslyAllowMutability: true, +}) From 1494082df10113634223ecbf3a29f7db0b9f798a Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 26 Aug 2024 11:14:09 +0900 Subject: [PATCH 2/6] =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QLine.js | 2 + src/components/fabric/QPolygon.js | 3 + src/hooks/useCanvas.js | 20 --- src/hooks/useCanvasEvent.js | 268 +++++++++++++++--------------- 4 files changed, 138 insertions(+), 155 deletions(-) diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 9604ec7c..55765279 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -11,6 +11,7 @@ export const QLine = fabric.util.createClass(fabric.Line, { direction: null, idx: 0, area: 0, + children: [], initialize: function (points, options, canvas) { this.callSuper('initialize', points, { ...options, selectable: options.selectable ?? false }) if (options.id) { @@ -122,6 +123,7 @@ export const QLine = fabric.util.createClass(fabric.Line, { lockRotation: true, lockScalingX: true, lockScalingY: true, + parent: this, name: 'lengthText', }) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 28a7d84a..c5093f91 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -17,6 +17,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { cells: [], parentId: null, innerLines: [], + children: [], initialize: function (points, options, canvas) { // 소수점 전부 제거 points.forEach((point) => { @@ -195,6 +196,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { lockScalingY: true, idx: i, name: 'lengthText', + parent: this, }) this.texts.push(text) @@ -271,6 +273,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { name: 'cell', idx: idx, parentId: this.id, + parent: this, }) idx++ diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index abcb22cc..42fe035d 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -179,25 +179,6 @@ export function useCanvas(id) { }) } - /** - * 선택한 도형을 삭제한다. - */ - const handleDelete = () => { - const targets = canvas?.getActiveObjects() - if (targets?.length === 0) { - alert('삭제할 대상을 선택해주세요.') - return - } - - if (!confirm('정말로 삭제하시겠습니까?')) { - return - } - - targets?.forEach((target) => { - canvas?.remove(target) - }) - } - /** * 페이지 내 캔버스 저장 * todo : 현재는 localStorage에 그냥 저장하지만 나중에 변경해야함 @@ -469,7 +450,6 @@ export function useCanvas(id) { handleUndo, handleRedo, handleCopy, - handleDelete, handleSave, handlePaste, handleRotate, diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index ea5256e6..89a15b3a 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -12,16 +12,112 @@ export function useCanvasEvent() { // 기본적인 이벤트 필요시 추가 const attachDefaultEventOnCanvas = () => { removeEventOnCanvas() - canvas?.on('object:added', onChange) - canvas?.on('object:added', addEventOnObject) - canvas?.on('object:modified', onChange) - canvas?.on('object:removed', onChange) + canvas?.on('object:added', objectEvent.onChange) + canvas?.on('object:added', objectEvent.addEvent) + canvas?.on('object:modified', objectEvent.onChange) + canvas?.on('object:removed', objectEvent.onChange) canvas?.on('selection:cleared', selectionEvent.cleared) canvas?.on('selection:created', selectionEvent.created) canvas?.on('selection:updated', selectionEvent.updated) canvas?.on('object:added', () => { document.addEventListener('keydown', handleKeyDown) }) + canvas?.on('object:removed', objectEvent.removed) + } + + const objectEvent = { + onChange: (e) => { + const target = e.target + if (target) { + // settleDown(target) + } + }, + addEvent: (e) => { + const target = e.target + + if (target.type === 'QPolygon' || target.type === 'QLine') { + const textObjs = canvas?.getObjects().filter((obj) => obj.name === 'lengthText') + textObjs.forEach((obj) => { + obj.bringToFront() + }) + } + + if (target.name === 'cell') { + target.on('mousedown', () => { + if (target.get('selected')) { + target.set({ selected: false }) + target.set({ fill: '#BFFD9F' }) + } else { + target.set({ selected: true }) + target.set({ fill: 'red' }) + } + canvas?.renderAll() + }) + } + + if (target.name === 'trestle') { + target.on('mousedown', () => { + if (target.defense === 'north') { + alert('북쪽은 선택 불가합니다.') + return + } + if (target.get('selected')) { + target.set({ strokeWidth: 1 }) + target.set({ strokeDashArray: [5, 5] }) + target.set({ selected: false }) + } else { + target.set({ strokeWidth: 5 }) + target.set({ strokeDashArray: [0, 0] }) + target.set({ selected: true }) + } + canvas?.renderAll() + }) + } + + if (target.name === 'lengthText') { + const x = target.left + const y = target.top + target.on('selected', (e) => { + Object.keys(target.controls).forEach((controlKey) => { + target.setControlVisible(controlKey, false) + }) + }) + target.on('moving', (e) => { + if (target.parentDirection === 'left' || target.parentDirection === 'right') { + const minX = target.minX + const maxX = target.maxX + + if (target.left <= minX) { + target.set({ left: minX, top: y }) + } else if (target.left >= maxX) { + target.set({ left: maxX, top: y }) + } else { + target.set({ top: y }) + } + } else if (target.parentDirection === 'top' || target.parentDirection === 'bottom') { + const minY = target.minY + const maxY = target.maxY + + if (target.top <= minY) { + target.set({ left: x, top: minY }) + } else if (target.top >= maxY) { + target.set({ left: x, top: maxY }) + } else { + target.set({ left: x }) + } + } + canvas?.renderAll() + }) + } + }, + removed: (e) => { + const whiteList = ['mouseLine', 'guideLine'] + + if (whiteList.includes(e.target.name)) { + return + } + console.log('removed', e) + }, } const selectionEvent = { @@ -38,146 +134,15 @@ export function useCanvasEvent() { }, } - const onChange = (e) => { - const target = e.target - if (target) { - // settleDown(target) - } - } - const removeEventOnCanvas = () => { canvas?.off('object:added') canvas?.off('object:modified') canvas?.off('object:removed') - canvas?.off('object:added') canvas?.off('selection:cleared') canvas?.off('selection:created') canvas?.off('selection:updated') } - const addEventOnObject = (e) => { - const target = e.target - - if (target.type === 'QPolygon' || target.type === 'QLine') { - const textObjs = canvas?.getObjects().filter((obj) => obj.name === 'lengthText') - textObjs.forEach((obj) => { - obj.bringToFront() - }) - } - - if (target.name === 'cell') { - target.on('mousedown', () => { - if (target.get('selected')) { - target.set({ selected: false }) - target.set({ fill: '#BFFD9F' }) - } else { - target.set({ selected: true }) - target.set({ fill: 'red' }) - } - canvas?.renderAll() - }) - } - - if (target.name === 'trestle') { - target.on('mousedown', () => { - if (target.defense === 'north') { - alert('북쪽은 선택 불가합니다.') - return - } - if (target.get('selected')) { - target.set({ strokeWidth: 1 }) - target.set({ strokeDashArray: [5, 5] }) - target.set({ selected: false }) - } else { - target.set({ strokeWidth: 5 }) - target.set({ strokeDashArray: [0, 0] }) - target.set({ selected: true }) - } - canvas?.renderAll() - }) - } - - if (target.name === 'lengthText') { - const x = target.left - const y = target.top - target.on('selected', (e) => { - Object.keys(target.controls).forEach((controlKey) => { - target.setControlVisible(controlKey, false) - }) - }) - target.on('moving', (e) => { - if (target.parentDirection === 'left' || target.parentDirection === 'right') { - const minX = target.minX - const maxX = target.maxX - - if (target.left <= minX) { - target.set({ left: minX, top: y }) - } else if (target.left >= maxX) { - target.set({ left: maxX, top: y }) - } else { - target.set({ top: y }) - } - } else if (target.parentDirection === 'top' || target.parentDirection === 'bottom') { - const minY = target.minY - const maxY = target.maxY - - if (target.top <= minY) { - target.set({ left: x, top: minY }) - } else if (target.top >= maxY) { - target.set({ left: x, top: maxY }) - } else { - target.set({ left: x }) - } - } - canvas?.renderAll() - }) - } - } - - // 마우스 가로, 세로선 그리기 - const drawMouseLines = (e) => { - // 현재 마우스 포인터의 위치를 가져옵니다. - const pointer = canvas?.getPointer(e.e) - - // 기존에 그려진 가이드라인을 제거합니다. - removeMouseLines() - - if (canvas?.getActiveObject()) { - return - } - - // 가로선을 그립니다. - const horizontalLine = new fabric.Line([0, pointer.y, canvasSize.horizontal, pointer.y], { - stroke: 'black', - strokeWidth: 1, - selectable: false, - name: 'mouseLine', - }) - - // 세로선을 그립니다. - const verticalLine = new fabric.Line([pointer.x, 0, pointer.x, canvasSize.vertical], { - stroke: 'black', - strokeWidth: 1, - selectable: false, - name: 'mouseLine', - }) - - // 선들을 캔버스에 추가합니다. - canvas?.add(horizontalLine, verticalLine) - - // 캔버스를 다시 그립니다. - canvas?.renderAll() - } - - //가로, 세로 선 삭제 - const removeMouseLines = () => { - if (canvas?._objects.length > 0) { - const mouseLines = canvas?._objects.filter((obj) => obj.name === 'mouseLine') - mouseLines.forEach((item) => canvas?.remove(item)) - } - canvas?.renderAll() - } - /** * 각종 키보드 이벤트 * https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values @@ -216,6 +181,16 @@ export function useCanvasEvent() { case 'Esc': // IE/Edge에서 사용되는 값 case 'Escape': break + + case 'z': + if (!e.ctrlKey) { + return + } + + console.log('뒤로가기') + + break + default: return // 키 이벤트를 처리하지 않는다면 종료합니다. } @@ -235,6 +210,7 @@ export function useCanvasEvent() { } targetObj.set({ top: top }) + targetObj.fire('modified') canvas?.renderAll() } @@ -251,6 +227,7 @@ export function useCanvasEvent() { } targetObj.set({ top: top }) + targetObj.fire('modified') canvas?.renderAll() } @@ -267,6 +244,7 @@ export function useCanvasEvent() { } targetObj.set({ left: left }) + targetObj.fire('modified') canvas?.renderAll() } @@ -283,9 +261,29 @@ export function useCanvasEvent() { } targetObj.set({ left: left }) + targetObj.fire('modified') canvas?.renderAll() } + /** + * 선택한 도형을 삭제한다. + */ + const handleDelete = () => { + const targets = canvas?.getActiveObjects() + if (targets?.length === 0) { + alert('삭제할 대상을 선택해주세요.') + return + } + + if (!confirm('정말로 삭제하시겠습니까?')) { + return + } + + targets?.forEach((target) => { + canvas?.remove(target) + }) + } + return { setCanvasForEvent, attachDefaultEventOnCanvas, From 3871c7d0d1eba1b244bc8d86bc26b26554c56dc3 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Mon, 26 Aug 2024 12:36:15 +0900 Subject: [PATCH 3/6] =?UTF-8?q?=EA=B7=B8=EB=A6=AC=EB=93=9C=20=EC=9E=84?= =?UTF-8?q?=EC=9D=98=20=EC=84=A4=EC=A0=95=20=ED=9D=A1=EC=B0=A9=EC=A0=90=20?= =?UTF-8?q?=EC=9E=91=EC=97=85,=20=EA=B7=B8=EB=A6=AC=EB=93=9C=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 3 +- src/components/SettingsModal.jsx | 180 +++++++++++-------------------- src/hooks/useMode.js | 48 +++++---- 3 files changed, 90 insertions(+), 141 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 7467a634..3fce8640 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -80,7 +80,6 @@ export default function Roof2(props) { setMode, changeMode, handleClear, - fillCellInPolygon, zoomIn, zoomOut, zoom, @@ -580,7 +579,7 @@ export default function Roof2(props) { > 그리드 설정 - + ) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 11cc0ec2..c7f2f5b2 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -123,9 +123,13 @@ export function useMode() { }, [guideLineInfo]) const drawMouseLines = (e) => { + console.log('guideLineInfo', guideLineInfo) + let isGuideLineMode = false, isGuideDotMode = false - let guideDotLength, guideLineLength, horizontalLineArray, verticalLineArray + let guideDotLength, guideLineLengthHori, guideLineLengthVert, horizontalLineArray, verticalLineArray + + console.log() if (isObjectNotEmpty(guideLineInfo)) { const guideLineState = guideLineInfo.filter((item) => item.guideMode === 'guideLine') @@ -136,13 +140,15 @@ export function useMode() { isGuideDotMode = guideDotState.length > 0 if (isGuideDotMode) { - guideDotLength = Number(guideDotState[0].moduleLength) + guideLineLengthHori = Number(guideDotState[0].moduleHoriLength) + guideLineLengthVert = Number(guideDotState[0].moduleVertLength) } if (isGuideLineMode) { horizontalLineArray = [...guideLineState[0].horizontalLineArray] verticalLineArray = [...guideLineState[0].verticalLineArray] - guideLineLength = Number(guideLineState[0].moduleLength) + guideLineLengthHori = Number(guideLineState[0].moduleHoriLength) + guideLineLengthVert = Number(guideLineState[0].moduleVertLength) } } @@ -161,17 +167,17 @@ export function useMode() { const xDiff = Math.abs(pointer.x - closetVerticalLine.x1) const yDiff = Math.abs(pointer.y - closestHorizontalLine.y1) - const x = pointer.x - guideLineLength * Math.floor(pointer.x / guideLineLength) - const y = pointer.y - guideLineLength * Math.floor(pointer.y / guideLineLength) + const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori) + const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert) - const xRate = x / guideLineLength - const yRate = y / guideLineLength + const xRate = x / guideLineLengthHori + const yRate = y / guideLineLengthVert const isAttachX = xRate >= 0.4 && xRate <= 0.7 const isAttachY = yRate >= 0.4 && yRate <= 0.7 if (isAttachX && isAttachY) { - newX = Math.floor(pointer.x / guideLineLength) * guideLineLength + guideLineLength / 2 - newY = Math.floor(pointer.y / guideLineLength) * guideLineLength + guideLineLength / 2 + newX = Math.floor(pointer.x / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2 + newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2 } else { if (Math.min(xDiff, yDiff) <= 20) { if (xDiff < yDiff) { @@ -184,17 +190,17 @@ export function useMode() { } } } else if (isGuideDotMode && mode === Mode.EDIT) { - const x = pointer.x - guideDotLength * Math.floor(pointer.x / guideDotLength) - const y = pointer.y - guideDotLength * Math.floor(pointer.y / guideDotLength) + const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori) + const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert) - const xRate = x / guideDotLength - const yRate = y / guideDotLength + const xRate = x / guideLineLengthHori + const yRate = y / guideLineLengthVert const isAttachX = xRate >= 0.4 && xRate <= 0.7 const isAttachY = yRate >= 0.4 && yRate <= 0.7 if (isAttachX && isAttachY) { - newX = Math.floor(pointer.x / guideDotLength) * guideDotLength + guideDotLength / 2 - newY = Math.floor(pointer.y / guideDotLength) * guideDotLength + guideDotLength / 2 + newX = Math.floor(pointer.x / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2 + newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2 } } else if (isGuideLineMode && mode === Mode.EDIT) { const closestHorizontalLine = getClosestHorizontalLine(pointer, horizontalLineArray) @@ -202,17 +208,17 @@ export function useMode() { const xDiff = Math.abs(pointer.x - closetVerticalLine.x1) const yDiff = Math.abs(pointer.y - closestHorizontalLine.y1) - const x = pointer.x - guideLineLength * Math.floor(pointer.x / guideLineLength) - const y = pointer.y - guideLineLength * Math.floor(pointer.y / guideLineLength) + const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori) + const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert) - const xRate = x / guideLineLength - const yRate = y / guideLineLength + const xRate = x / guideLineLengthHori + const yRate = y / guideLineLengthVert const isAttachX = xRate >= 0.4 && xRate <= 0.7 const isAttachY = yRate >= 0.4 && yRate <= 0.7 if (isAttachX && isAttachY) { - newX = Math.floor(pointer.x / guideLineLength) * guideLineLength + guideLineLength / 2 - newY = Math.floor(pointer.y / guideLineLength) * guideLineLength + guideLineLength / 2 + newX = Math.floor(pointer.x / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2 + newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2 } else { if (Math.min(xDiff, yDiff) <= 20) { if (xDiff < yDiff) { From 68365493e2ebdb70c8b88887e5a82a1b0d25ee8d Mon Sep 17 00:00:00 2001 From: yjnoh Date: Mon, 26 Aug 2024 14:49:58 +0900 Subject: [PATCH 4/6] =?UTF-8?q?4=EA=B0=81=ED=98=95=20=EC=85=80=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 73 ++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index c7f2f5b2..2d7356a4 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -123,14 +123,10 @@ export function useMode() { }, [guideLineInfo]) const drawMouseLines = (e) => { - console.log('guideLineInfo', guideLineInfo) - let isGuideLineMode = false, isGuideDotMode = false let guideDotLength, guideLineLengthHori, guideLineLengthVert, horizontalLineArray, verticalLineArray - console.log() - if (isObjectNotEmpty(guideLineInfo)) { const guideLineState = guideLineInfo.filter((item) => item.guideMode === 'guideLine') const guideDotState = guideLineInfo.filter((item) => item.guideMode === 'guideDot') @@ -4217,38 +4213,49 @@ export function useMode() { } } - //셀이 생성될 지붕의 흐름방향을 정함 - templateCenterLine.some((centerLine) => { + console.log('templateCenterLine', templateCenterLine) + + if (templateCenterLine.length > 0) { + //셀이 생성될 지붕의 흐름방향을 정함 + templateCenterLine.some((centerLine) => { + if (templateType === 2) { + trestlePolygon.set({ + referenceDirection: referenceDirection, + startIndex: parallelPoint, + }) //기준면 방향 + trestlePolygon.points.forEach((trestleLine, index) => { + if (trestleLine.x === centerLine.x1 - 12) { + trestlePolygon.set({ wallDirection: 'left' }) + return true + } else if (trestleLine.x === centerLine.x1 + 12) { + trestlePolygon.set({ wallDirection: 'right' }) + return true + } + }) + } else if (templateType === 3) { + trestlePolygon.set({ + referenceDirection: referenceDirection, + startIndex: parallelPoint, + }) //기준면 방향 + trestlePolygon.points.forEach((trestleLine, index) => { + if (trestleLine.y === centerLine.y1 - 12) { + trestlePolygon.set({ wallDirection: 'top' }) + return true + } else if (trestleLine.y === centerLine.y1 + 12) { + trestlePolygon.set({ wallDirection: 'bottom' }) + return true + } + }) + } + }) + } else { if (templateType === 2) { - trestlePolygon.set({ - referenceDirection: referenceDirection, - startIndex: parallelPoint, - }) //기준면 방향 - trestlePolygon.points.forEach((trestleLine, index) => { - if (trestleLine.x === centerLine.x1 - 12) { - trestlePolygon.set({ wallDirection: 'left' }) - return true - } else if (trestleLine.x === centerLine.x1 + 12) { - trestlePolygon.set({ wallDirection: 'right' }) - return true - } - }) + index === 0 ? trestlePolygon.set({ wallDirection: 'left' }) : trestlePolygon.set({ wallDirection: 'right' }) } else if (templateType === 3) { - trestlePolygon.set({ - referenceDirection: referenceDirection, - startIndex: parallelPoint, - }) //기준면 방향 - trestlePolygon.points.forEach((trestleLine, index) => { - if (trestleLine.y === centerLine.y1 - 12) { - trestlePolygon.set({ wallDirection: 'top' }) - return true - } else if (trestleLine.y === centerLine.y1 + 12) { - trestlePolygon.set({ wallDirection: 'bottom' }) - return true - } - }) + index === 0 ? trestlePolygon.set({ wallDirection: 'top' }) : trestlePolygon.set({ wallDirection: 'bottom' }) } - }) + trestlePolygon.set({ referenceDirection: 'none' }) + } /** * 가대 선택 이벤트 From 795f5fc30f3f512fe0fe8b1771b79619c78ce1b8 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 26 Aug 2024 15:45:36 +0900 Subject: [PATCH 5/6] =?UTF-8?q?clear=20=EC=8B=9C=20=EB=B9=84=EC=9B=8C?= =?UTF-8?q?=EC=A3=BC=EB=8A=94=20=EB=82=B4=EC=9A=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 2d7356a4..afb1f417 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -663,9 +663,12 @@ export function useMode() { editMode: (options) => { // const pointer = canvas?.getPointer(options.e) + let pointer = canvas?.getPointer(options.e) const mouseLines = canvas?._objects.filter((obj) => obj.name === 'mouseLine') - const pointer = calculateIntersection(mouseLines[0], mouseLines[1]) + /*if (calculateIntersection(mouseLines[0], mouseLines[1])) { + pointer = calculateIntersection(mouseLines[0], mouseLines[1]) + }*/ const circle = new fabric.Circle({ radius: 5, @@ -951,6 +954,8 @@ export function useMode() { points.current = [] historyPoints.current = [] historyLines.current = [] + setRoof(null) + setWall(null) setSelectedCellRoofArray([]) //셀 그린거 삭제 } From e2ce94767ceededce0513351cb0d6b969d1a8067 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Mon, 26 Aug 2024 16:23:15 +0900 Subject: [PATCH 6/6] =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=ED=81=B4=EB=A6=AD?= =?UTF-8?q?=EC=8B=9C=20=EC=98=A4=EB=A5=98=20validator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index afb1f417..e624cf4b 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -1494,6 +1494,11 @@ export function useMode() { } const applyTemplateA = () => { + if (historyPoints.current.length === 0) { + changeMode(canvas, Mode.EDIT) + return + } + changeMode(canvas, Mode.EDIT) const polygon = drawWallPolygon(false) // handleClear() @@ -2940,7 +2945,11 @@ export function useMode() { * 템플릿 B 적용 */ const applyTemplateB = () => { - changeMode(canvas, Mode.EDIT) + if (historyPoints.current.length === 0) { + changeMode(canvas, Mode.EDIT) + return + } + const polygon = drawWallPolygon(false) const params = { eaves: 50, @@ -4218,8 +4227,6 @@ export function useMode() { } } - console.log('templateCenterLine', templateCenterLine) - if (templateCenterLine.length > 0) { //셀이 생성될 지붕의 흐름방향을 정함 templateCenterLine.some((centerLine) => {