diff --git a/src/common/common.js b/src/common/common.js index ae00ec78..91a9583a 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -11,6 +11,7 @@ export const Mode = { FILL_CELLS: 'fillCells', //태양광셀 모드 CELL_POWERCON: 'cellPowercon', //파워콘 DRAW_HELP_LINE: 'drawHelpLine', // 보조선 그리기 모드 지붕 존재해야함 + ADSORPTION_POINT: 'adsorptionPoint', //흡착점 모드 DEFAULT: 'default', } diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index e3d24216..794c0265 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -632,6 +632,13 @@ export default function Roof2(props) { + - diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index 42fe035d..bcc8b7d7 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -3,8 +3,8 @@ import { fabric } from 'fabric' import { actionHandler, anchorWrapper, polygonPositionHandler } from '@/util/canvas-util' -import { useRecoilState, useSetRecoilState } from 'recoil' -import { canvasSizeState, fontSizeState, guidePointModeState } from '@/store/canvasAtom' +import { useRecoilState } from 'recoil' +import { canvasSizeState, fontSizeState } from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' import { QPolygon } from '@/components/fabric/QPolygon' import { defineQLine } from '@/util/qline-utils' @@ -20,7 +20,6 @@ export function useCanvas(id) { const [canvasSize] = useRecoilState(canvasSizeState) const [fontSize] = useRecoilState(fontSizeState) const { setCanvasForEvent, attachDefaultEventOnCanvas } = useCanvasEvent() - const setGuidePointMode = useSetRecoilState(guidePointModeState) /** * 처음 셋팅 @@ -382,7 +381,6 @@ export function useCanvas(id) { } const setCanvasBackgroundWithDots = (canvas, gap) => { - setGuidePointMode(true) // Create a new canvas and fill it with dots const tempCanvas = new fabric.StaticCanvas() tempCanvas.setDimensions({ diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index afb1f417..4df9698a 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react' import { calculateIntersection, distanceBetweenPoints, - findTopTwoIndexesByDistance, + findClosestPoint, getCenterPoint, getClosestHorizontalLine, getClosestVerticalLine, @@ -17,7 +17,6 @@ import { compassState, drewRoofCellsState, fontSizeState, - guidePointModeState, modeState, roofPolygonArrayState, roofPolygonPatternArrayState, @@ -47,7 +46,6 @@ export function useMode() { const [sortedArray, setSortedArray] = useRecoilState(sortedPolygonArray) const [roof, setRoof] = useRecoilState(roofState) const [wall, setWall] = useRecoilState(wallState) - const isGuidePointMode = useRecoilValue(guidePointModeState) const [endPoint, setEndPoint] = useState(null) @@ -104,10 +102,12 @@ export function useMode() { useEffect(() => { canvas?.off('mouse:move') canvas?.on('mouse:move', drawMouseLines) + changeMode(canvas, mode) + /* if (mode === Mode.EDIT) { canvas?.off('mouse:down') canvas?.on('mouse:down', mouseEvent.editMode) - } + }*/ }, [mode]) useEffect(() => { @@ -122,6 +122,7 @@ export function useMode() { } }, [guideLineInfo]) + // 마우스 보조선 가로선, 세로선 그리기 const drawMouseLines = (e) => { let isGuideLineMode = false, isGuideDotMode = false @@ -157,74 +158,86 @@ export function useMode() { let newX = pointer.x let newY = pointer.y - if (isGuideLineMode && isGuideDotMode && mode === Mode.EDIT) { - const closestHorizontalLine = getClosestHorizontalLine(pointer, horizontalLineArray) - const closetVerticalLine = getClosestVerticalLine(pointer, verticalLineArray) - const xDiff = Math.abs(pointer.x - closetVerticalLine.x1) - const yDiff = Math.abs(pointer.y - closestHorizontalLine.y1) + //흡착점 있는지 확인 + const adsorptionPointList = canvas?._objects.filter((obj) => obj.name === 'adsorptionPoint') - const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori) - const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert) + if (mode === Mode.EDIT || mode === Mode.ADSORPTION_POINT) { + let adsorptionPoint = adsorptionPointList.length > 0 ? findClosestPoint(pointer, adsorptionPointList) : null - 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 (isGuideLineMode && isGuideDotMode) { + const closestHorizontalLine = getClosestHorizontalLine(pointer, horizontalLineArray) + const closetVerticalLine = getClosestVerticalLine(pointer, verticalLineArray) + const xDiff = Math.abs(pointer.x - closetVerticalLine.x1) + const yDiff = Math.abs(pointer.y - closestHorizontalLine.y1) - if (isAttachX && isAttachY) { - 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) { - newX = closetVerticalLine.x1 - newY = pointer.y - } else { - newX = pointer.x - newY = closestHorizontalLine.y1 + const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori) + const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert) + + 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 / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2 + newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2 + } else { + if (Math.min(xDiff, yDiff) <= 20) { + if (xDiff < yDiff) { + newX = closetVerticalLine.x1 + newY = pointer.y + } else { + newX = pointer.x + newY = closestHorizontalLine.y1 + } + } + } + } else if (isGuideDotMode) { + const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori) + const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert) + + 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 / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2 + newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2 + } + } else if (isGuideLineMode) { + const closestHorizontalLine = getClosestHorizontalLine(pointer, horizontalLineArray) + const closetVerticalLine = getClosestVerticalLine(pointer, verticalLineArray) + const xDiff = Math.abs(pointer.x - closetVerticalLine.x1) + const yDiff = Math.abs(pointer.y - closestHorizontalLine.y1) + + const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori) + const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert) + + 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 / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2 + newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2 + } else { + if (Math.min(xDiff, yDiff) <= 20) { + if (xDiff < yDiff) { + newX = closetVerticalLine.x1 + newY = pointer.y + } else { + newX = pointer.x + newY = closestHorizontalLine.y1 + } } } } - } else if (isGuideDotMode && mode === Mode.EDIT) { - const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori) - const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert) - 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 / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2 - newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2 - } - } else if (isGuideLineMode && mode === Mode.EDIT) { - const closestHorizontalLine = getClosestHorizontalLine(pointer, horizontalLineArray) - const closetVerticalLine = getClosestVerticalLine(pointer, verticalLineArray) - const xDiff = Math.abs(pointer.x - closetVerticalLine.x1) - const yDiff = Math.abs(pointer.y - closestHorizontalLine.y1) - - const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori) - const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert) - - 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 / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2 - newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2 - } else { - if (Math.min(xDiff, yDiff) <= 20) { - if (xDiff < yDiff) { - newX = closetVerticalLine.x1 - newY = pointer.y - } else { - newX = pointer.x - newY = closestHorizontalLine.y1 - } - } + if (adsorptionPoint && distanceBetweenPoints(pointer, adsorptionPoint) < 20) { + newX = adsorptionPoint.left + newY = adsorptionPoint.top } } @@ -330,13 +343,9 @@ export function useMode() { const pointer = canvas?.getPointer(e.e) let newX, newY - if (isGuidePointMode && mode === Mode.EDIT) { - newX = Math.round(pointer.x / 200) * 200 - newY = Math.round(pointer.y / 200) * 200 - } else { - newX = pointer.x - newY = pointer.y - } + + newX = pointer.x + newY = pointer.y // 마우스 포인터 위치랑 endPoint를 연결하는 line 생성 const line = new fabric.Line([endPoint.left, endPoint.top, newX, newY], { @@ -373,6 +382,9 @@ export function useMode() { canvas?.on('selection:created', addSelectCreatedEvent) canvas?.on('selection:cleared', addSelectClearedEvent) break + case 'adsorptionPoint': + canvas?.on('mouse:down', mouseEvent.adsorptionPoint) + break case 'default': canvas?.off('mouse:down') break @@ -605,9 +617,9 @@ export function useMode() { const changeMode = (canvas, mode) => { setMode(mode) - // mode변경 시 이전 이벤트 제거 setCanvas(canvas) + // mode별 이벤트 변경 changeMouseEvent(mode) changeKeyboardEvent(mode) @@ -661,14 +673,11 @@ export function useMode() { canvas?.renderAll() }, editMode: (options) => { - // const pointer = canvas?.getPointer(options.e) - let pointer = canvas?.getPointer(options.e) - const mouseLines = canvas?._objects.filter((obj) => obj.name === 'mouseLine') - /*if (calculateIntersection(mouseLines[0], mouseLines[1])) { - pointer = calculateIntersection(mouseLines[0], mouseLines[1]) - }*/ + if (getInterSectPointByMouseLine()) { + pointer = getInterSectPointByMouseLine() + } const circle = new fabric.Circle({ radius: 5, @@ -676,6 +685,8 @@ export function useMode() { stroke: 'red', // 원 테두리 색상을 검은색으로 설정합니다. left: pointer.x, top: pointer.y, + x: pointer.x, + y: pointer.y, originX: 'center', originY: 'center', selectable: false, @@ -827,6 +838,43 @@ export function useMode() { rect.set({ height: Math.abs(origY - pointer.y) }) }) }, + // 흡착점 추가 + adsorptionPoint(o) { + const pointer = canvas.getPointer(o.e) + let newX = pointer.x + let newY = pointer.y + + if (getInterSectPointByMouseLine()) { + const interSectPoint = getInterSectPointByMouseLine() + newX = interSectPoint.x + newY = interSectPoint.y + } + + const circle = new fabric.Circle({ + radius: 5, + fill: 'transparent', // 원 안을 비웁니다. + stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다. + left: newX, + top: newY, + originX: 'center', + originY: 'center', + x: newX - 5, + y: newY - 5, + selectable: false, + name: 'adsorptionPoint', + }) + + canvas.add(circle) + canvas.renderAll() + }, + } + + const getInterSectPointByMouseLine = () => { + const mouseLines = canvas?._objects.filter((obj) => obj.name === 'mouseLine') + if (mouseLines.length !== 2) { + return null + } + return calculateIntersection(mouseLines[0], mouseLines[1]) } const pushHistoryLine = (line) => { diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index fafe26a1..c2b245d7 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -10,11 +10,6 @@ export const modeState = atom({ default: 'default', }) -export const guidePointModeState = atom({ - key: 'guidePointModeState', - default: false, -}) - export const guideModeLineState = atom({ key: 'guideLineModeState', default: false,