diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 93e03304..ecbc083b 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -5,7 +5,7 @@ import { useEffect, useRef, useState } from 'react' import { v4 as uuidv4 } from 'uuid' import { useMode } from '@/hooks/useMode' import { Mode } from '@/common/common' -import { Button } from '@nextui-org/react' +import { Button, Input } from '@nextui-org/react' import RangeSlider from './ui/RangeSlider' import { useRecoilState, useRecoilValue } from 'recoil' import { @@ -15,6 +15,7 @@ import { compassState, currentObjectState, fontSizeState, + globalCompassState, roofMaterialState, roofState, sortedPolygonArray, @@ -24,20 +25,20 @@ import { } from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' import { getCanvasState, insertCanvasState } from '@/lib/canvas' -import { calculateIntersection, distanceBetweenPoints, getIntersectionPoint } from '@/util/canvas-util' +import { calculateIntersection } from '@/util/canvas-util' import { QPolygon } from '@/components/fabric/QPolygon' -import ThumbnailList from './ui/ThumbnailLIst' import QContextMenu from './common/context-menu/QContextMenu' import { modalContent, modalState } from '@/store/modalAtom' import { useAxios } from '@/hooks/useAxios' import QPolygonContextMenu from '@/components/common/context-menu/QPolygonContextMenu' import QLineContextMenu from '@/components/common/context-menu/QLineContextMenu' import QEmptyContextMenu from '@/components/common/context-menu/QEmptyContextMenu' -import { degreesToRadians, point, radiansToDegrees } from '@turf/turf' import InitSettingsModal from './InitSettingsModal' import GridSettingsModal from './GridSettingsModal' import { SurfaceShapeModal } from '@/components/ui/SurfaceShape' +import { drawDirectionStringToArrow } from '@/util/qpolygon-utils' +import ThumbnailList from '@/components/ui/ThumbnailLIst' export default function Roof2(props) { const { name, userId, email, isLoggedIn } = props @@ -105,6 +106,8 @@ export default function Roof2(props) { let imgPath useCadFile && (imgPath = `/cadImages/${cadFileName}`) + const [globalCampass, setGlobalCampass] = useRecoilState(globalCompassState) + const { mode, setMode, @@ -608,6 +611,10 @@ export default function Roof2(props) { const moduleConfiguration = () => { createRoofRack() } + + const setDirectionStringToArrow = () => { + drawDirectionStringToArrow(canvas, globalCampass) + } return ( <> {canvas && ( @@ -854,6 +861,58 @@ export default function Roof2(props) { )} +
+

각도 입력(0~360) 후 방향설정 클릭

+ { + const val = e.target.value.replace(/[^-0-9]/g, '') + if (val < 0 || val > 360) { + setGlobalCampass(0) + } else { + setGlobalCampass(Number(val)) + } + }} + /> + +
+
+ {/* Compass Circle */} +
+ {/* N, S, E, W Labels */} +
N
+
S
+
+ E +
+
+ W +
+
+ + {/* Compass Pointer */} +
+ {/* Red Upper Triangle */} +
+
+
{!canvas ? null : mode === Mode.DRAW_LINE ? ( diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index e4902c33..043a561f 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -428,6 +428,7 @@ export function useCanvas(id) { 'minY', 'x', 'y', + 'stickeyPoint', ]) const str = JSON.stringify(objs) diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index f2bbfa3a..a675b508 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -144,3 +144,9 @@ export const cadFileCompleteState = atom({ key: 'cadFileComplete', default: false, }) + +export const globalCompassState = atom({ + key: 'globalCompass', + default: 0, + dangerouslyAllowMutability: true, +}) diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index f89652f1..5e00b197 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -2717,7 +2717,12 @@ export const drawDirectionArrow = (polygon) => { let arrow = null let points = [] + if (polygon.arrow) { + polygon.canvas.remove(polygon.arrow) + } + let centerPoint = polygon.getCenterPoint() + let stickeyPoint const polygonMaxX = Math.max(...polygon.points.map((point) => point.x)) const polygonMinX = Math.min(...polygon.points.map((point) => point.x)) @@ -2736,6 +2741,8 @@ export const drawDirectionArrow = (polygon) => { { x: centerPoint.x - 20, y: polygonMinY - 50 }, { x: centerPoint.x - 20, y: polygonMinY - 20 }, ] + + stickeyPoint = { x: centerPoint.x, y: polygonMinY - 80 } break case 'south': points = [ @@ -2748,6 +2755,7 @@ export const drawDirectionArrow = (polygon) => { { x: centerPoint.x - 20, y: polygonMaxY + 50 }, { x: centerPoint.x - 20, y: polygonMaxY + 20 }, ] + stickeyPoint = { x: centerPoint.x, y: polygonMaxY + 80 } break case 'west': points = [ @@ -2760,6 +2768,8 @@ export const drawDirectionArrow = (polygon) => { { x: polygonMinX - 50, y: centerPoint.y - 20 }, { x: polygonMinX - 20, y: centerPoint.y - 20 }, ] + + stickeyPoint = { x: polygonMinX - 80, y: centerPoint.y } break case 'east': points = [ @@ -2772,16 +2782,227 @@ export const drawDirectionArrow = (polygon) => { { x: polygonMaxX + 50, y: centerPoint.y - 20 }, { x: polygonMaxX + 20, y: centerPoint.y - 20 }, ] + + stickeyPoint = { x: polygonMaxX + 80, y: centerPoint.y } break } arrow = new fabric.Polygon(points, { selectable: false, + name: 'arrow', fill: 'transparent', stroke: 'black', + direction: direction, + parent: polygon, + stickeyPoint: stickeyPoint, }) polygon.arrow = arrow polygon.canvas.add(arrow) polygon.canvas.renderAll() } + +/** + * 방향을 나타낸 화살표에 각도에 따라 글씨 추가 + * @param canvas + * @param compass + */ +export const drawDirectionStringToArrow = (canvas, compass, fontSize) => { + const arrows = canvas?.getObjects().filter((obj) => obj.name === 'arrow') + + if (arrows.length === 0) { + return + } + + const eastArrows = arrows.filter((arrow) => arrow.direction === 'east') + const westArrows = arrows.filter((arrow) => arrow.direction === 'west') + const northArrows = arrows.filter((arrow) => arrow.direction === 'north') + const southArrows = arrows.filter((arrow) => arrow.direction === 'south') + + let southText = '南' + let eastText = '東' + let westText = '西' + let northText = '北' + + if (compass === 0 || compass === 360) { + // 남,동,서 가능 + // 그대로 + } else if (compass < 45) { + //남(남남동),동(동북동),서(서남서) 가능 + //북(북북서) + southText = '南南東' + eastText = '東北東' + westText = '西南西' + northText = '北北西' + } else if (compass === 45) { + // 남, 서 가능 + // 남(남동) + // 서(남서) + // 북(북서) + // 동(북동) + southText = '南東' + westText = '南西' + northText = '北西' + eastText = '北東' + } else if (compass < 90) { + // 북(서북서) + // 동 (북북동) + // 남(동남동) + // 서(남남서) + northText = '北西北' + eastText = '北北東' + southText = '東南東' + westText = '南南西' + } else if (compass === 90) { + // 동(북) + // 서(남) + // 남(동) + // 북(서) + eastText = '北' + westText = '南' + southText = '東' + northText = '西' + } else if (compass < 135) { + // 남,서,북 가능 + // 동(북북서) + // 서(남남동) + // 남(동북동) + // 북(서남서) + eastText = '北北西' + westText = '南南東' + southText = '東北東' + northText = '西南西' + } else if (compass === 135) { + // 서,북 가능 + + // 서(남동) + // 북(남서) + // 남(북동) + // 동(북서) + + westText = '南東' + northText = '南西' + southText = '北東' + eastText = '北西' + } else if (compass < 180) { + // 북,동,서 가능 + // 북(남남서) + // 동(서북서) + // 남(북북동) + // 서(동남동) + + northText = '南南西' + eastText = '西北西' + southText = '北北東' + westText = '東南東' + } else if (compass === 180) { + // 북,동,서 가능 + // 북(남) + // 동(서) + // 남(북) + // 서(동) + northText = '南' + eastText = '西' + southText = '北' + westText = '東' + } else if (compass < 225) { + // 서,북,동 가능 + // 북(남남동) + // 동(서남서) + // 남(북북서) + // 서(동남동) + northText = '南南東' + eastText = '西南西' + southText = '北北西' + westText = '東南東' + } else if (compass === 225) { + // 북,동 가능 + // 북(남동) + // 동(남서) + // 남(북서) + // 서(북동) + northText = '南東' + eastText = '南西' + southText = '北西' + westText = '北東' + } else if (compass < 270) { + // 북동남 가능 + // 북(동남동) + // 동(남남서) + // 남(서북서) + // 서(북북동) + northText = '東南東' + eastText = '南南西' + southText = '西北西' + westText = '北北東' + } else if (compass === 270) { + // 북동남 가능 + // 북(동) + // 동(남) + // 남(서) + // 서(북) + northText = '東' + eastText = '南' + southText = '西' + westText = '北' + } else if (compass < 315) { + // 북,동,남 가능 + // 북(동북동) + // 동(남남동) + // 남(서남서) + // 서(북북서) + northText = '東北東' + eastText = '南南東' + southText = '西南西' + westText = '北北西' + } else if (compass === 315) { + // 동,남 가능 + // 북(북동) + // 동(남동) + // 남(남서) + // 서(북서) + northText = '北東' + eastText = '南東' + southText = '南西' + westText = '北西' + } else if (compass < 360) { + // 남,동,서 가능 + // 북(북북동) + // 동(동남동) + // 남(남남서) + // 서(서북서) + northText = '北北東' + eastText = '東南東' + southText = '南南西' + westText = '西北西' + } + + clearDirectionText(canvas) + + addTextByArrows(eastArrows, eastText, canvas) + addTextByArrows(westArrows, westText, canvas) + addTextByArrows(northArrows, northText, canvas) + addTextByArrows(southArrows, southText, canvas) +} + +const clearDirectionText = (canvas) => { + const texts = canvas.getObjects().filter((obj) => obj.name === 'directionText') + texts.forEach((text) => { + canvas.remove(text) + }) +} + +const addTextByArrows = (arrows, txt, canvas) => { + arrows.forEach((arrow, index) => { + const text = new fabric.Text(`${txt}${index + 1}`, { + fontSize: arrow.parent.fontSize, + fill: 'black', + originX: 'center', + originY: 'center', + name: 'directionText', + left: arrow.stickeyPoint.x, + top: arrow.stickeyPoint.y, + }) + canvas.add(text) + }) +}