diff --git a/.env.development b/.env.development
index 4c2c816c..9a1529ed 100644
--- a/.env.development
+++ b/.env.development
@@ -1,6 +1,6 @@
NEXT_PUBLIC_TEST="테스트변수입니다. development"
-NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080"
+ NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080"
# NEXT_PUBLIC_API_SERVER_PATH="http://localhost:8080"
DATABASE_URL="sqlserver://mssql.devgrr.kr:1433;database=qcast;user=qcast;password=Qwertqaz12345;trustServerCertificate=true"
diff --git a/package.json b/package.json
index cfafa961..7a9f1077 100644
--- a/package.json
+++ b/package.json
@@ -31,6 +31,7 @@
},
"devDependencies": {
"@turf/turf": "^7.0.0",
+ "dayjs": "^1.11.13",
"postcss": "^8",
"prettier": "^3.3.3",
"prisma": "^5.18.0",
diff --git a/qcast-front.iml b/qcast-front.iml
new file mode 100644
index 00000000..bef2a966
--- /dev/null
+++ b/qcast-front.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/[locale]/settings/page.jsx b/src/app/[locale]/settings/page.jsx
new file mode 100644
index 00000000..797c024c
--- /dev/null
+++ b/src/app/[locale]/settings/page.jsx
@@ -0,0 +1,16 @@
+import Hero from '@/components/Hero'
+import Settings from '@/components/Settings'
+import { initCheck } from '@/util/session-util'
+
+export default async function SettingsPage() {
+ await initCheck()
+
+ return (
+ <>
+
+
+
+
+ >
+ )
+}
diff --git a/src/components/GridSettingsModal.jsx b/src/components/GridSettingsModal.jsx
index 78e3c8a6..f1e77c94 100644
--- a/src/components/GridSettingsModal.jsx
+++ b/src/components/GridSettingsModal.jsx
@@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react'
import { Button, Checkbox, CheckboxGroup, RadioGroup, Radio, Input } from '@nextui-org/react'
import { useRecoilState, useRecoilValue } from 'recoil'
import { modalContent, modalState } from '@/store/modalAtom'
-import { guideLineState } from '@/store/canvasAtom'
+import { guideLineState, horiGuideLinesState, vertGuideLinesState } from '@/store/canvasAtom'
import { fabric } from 'fabric'
import { ColorPicker, useColor } from 'react-color-palette'
import 'react-color-palette/css'
@@ -18,6 +18,8 @@ export default function SettingsModal(props) {
const [open, setOpen] = useRecoilState(modalState)
const [guideLine, setGuideLine] = useRecoilState(guideLineState)
+ const [horiGuideLines, setHoriGuideLines] = useRecoilState(horiGuideLinesState)
+ const [vertGuideLines, setVertGuideLines] = useRecoilState(vertGuideLinesState)
const gridSettingArray = []
@@ -76,6 +78,7 @@ export default function SettingsModal(props) {
name: 'guideLine',
strokeDashArray: [5, 2],
opacity: 0.3,
+ direction: 'horizontal',
},
)
canvasProps.add(horizontalLine)
@@ -97,6 +100,7 @@ export default function SettingsModal(props) {
name: 'guideLine',
strokeDashArray: [5, 2],
opacity: 0.3,
+ direction: 'vertical',
},
)
canvasProps.add(verticalLine)
@@ -114,6 +118,16 @@ export default function SettingsModal(props) {
moduleHoriLength: moduleHoriLength,
}
gridSettingArray.push(recoilObj)
+ const newHoriGuideLines = [...horiGuideLines]
+ horizontalLineArray.forEach((line) => {
+ newHoriGuideLines.push(line)
+ })
+ const newVertGuideLines = [...vertGuideLines]
+ verticalLineArray.forEach((line) => {
+ newVertGuideLines.push(line)
+ })
+ setHoriGuideLines(newHoriGuideLines)
+ setVertGuideLines(newVertGuideLines)
}
if (gridCheckedValue.includes('dot')) {
@@ -187,6 +201,8 @@ export default function SettingsModal(props) {
guideLines?.forEach((item) => canvasProps.remove(item))
canvasProps.renderAll()
setGuideLine([])
+ setHoriGuideLines([])
+ setVertGuideLines([])
} else {
alert('그리드가 없습니다.')
return
diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx
index ec47b201..83ca1213 100644
--- a/src/components/Roof2.jsx
+++ b/src/components/Roof2.jsx
@@ -1,7 +1,7 @@
'use client'
import { useCanvas } from '@/hooks/useCanvas'
-import { useEffect, useRef, useState } from 'react'
+import { useCallback, useEffect, useRef, useState } from 'react'
import { v4 as uuidv4 } from 'uuid'
import { useMode } from '@/hooks/useMode'
import { Mode } from '@/common/common'
@@ -21,7 +21,7 @@ import {
} from '@/store/canvasAtom'
import { QLine } from '@/components/fabric/QLine'
import { getCanvasState, insertCanvasState } from '@/lib/canvas'
-import { calculateIntersection } from '@/util/canvas-util'
+import { calculateIntersection, distanceBetweenPoints } from '@/util/canvas-util'
import { QPolygon } from '@/components/fabric/QPolygon'
import ThumbnailList from './ui/ThumbnailLIst'
import QContextMenu from './common/context-menu/QContextMenu'
@@ -30,6 +30,7 @@ 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, radiansToDegrees } from '@turf/turf'
import InitSettingsModal from './InitSettingsModal'
import GridSettingsModal from './GridSettingsModal'
@@ -573,6 +574,1151 @@ export default function Roof2(props) {
canvas?.renderAll()
}
+ const createTemplate1 = () => {
+ const length1 = prompt('1번')
+ const length2 = prompt('2번')
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x, y: pointer.y - parseInt(length2) / 2 },
+ { x: pointer.x - parseInt(length1) / 2, y: pointer.y + parseInt(length1) / 2 },
+ { x: pointer.x + parseInt(length1) / 2, y: pointer.y + parseInt(length1) / 2 },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+
+ const createPentagon2 = () => {
+ const a = 400 //Number(prompt('a'))
+ const b = 200 //Number(prompt('b'))
+ const c = 250 //Number(prompt('c'))
+ const d = 150 //Number(prompt('d'))
+
+ const t = (c * (a - b)) / (200 + c)
+
+ const t2 = Math.sqrt(c * c + t * t)
+
+ const t3 = Math.sqrt((c - d) * (c - d) + (a - b - t) * (a - b - t))
+
+ const angle = Math.atan(t2 / t)
+ const angle2 = Math.atan(t3 / (a - b - t))
+
+ let isDrawing = true
+ let pentagon
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+
+ pentagon = new QPolygon(
+ [
+ { x: pointer.x - a / 2, y: pointer.y + a / 2 - d },
+ { x: pointer.x + a / 2, y: pointer.y + a / 2 - d },
+ { x: pointer.x + a / 2, y: pointer.y + a / 2 - d - d },
+ { x: pointer.x + a / 2 - b, y: pointer.y + a / 2 - d - d },
+ {
+ x: pointer.x + a / 2 - b - t3 * Math.cos(angle),
+ y: pointer.y + a / 2 - d - d - t3 * Math.sin(angle),
+ },
+ /*{
+ x: pointer.x - a / 2 + t2 * Math.cos(angle),
+ y: pointer.y + a / 2 - d - t2 * Math.sin(angle),
+ },*/
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'gray',
+ strokeWidth: 1,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(pentagon)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ pentagon.set('name', 'roof')
+ pentagon.set('stroke', 2)
+ canvas?.renderAll()
+ })
+ }
+
+ const createTemplate2 = () => {
+ const length1 = prompt('1번')
+ const length2 = prompt('2번')
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 },
+ { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 },
+ { x: pointer.x + length1 / 2, y: pointer.y - length2 / 2 },
+ { x: pointer.x - length1 / 2, y: pointer.y - length2 / 2 },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+
+ const createTemplate3 = () => {
+ const length1 = Number(prompt('1번'))
+ const length2 = Number(prompt('2번'))
+ const length3 = Number(prompt('3번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 },
+ { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 },
+ { x: pointer.x + length3 / 2, y: pointer.y - length2 / 2 },
+ { x: pointer.x - length3 / 2, y: pointer.y - length2 / 2 },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+
+ const createTemplate4 = () => {
+ const length1 = Number(prompt('1번'))
+ const length2 = Number(prompt('2번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 },
+ { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 },
+ { x: pointer.x + length1 / 2, y: pointer.y - length2 / 2 },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+
+ const createTemplate5 = () => {
+ const length1 = Number(prompt('1번'))
+ const length2 = Number(prompt('2번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 },
+ { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 },
+ { x: pointer.x - length1 / 2, y: pointer.y - length2 / 2 },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+
+ const createTemplate6 = () => {
+ const length1 = Number(prompt('1번'))
+ const length2 = Number(prompt('2번'))
+ const length3 = Number(prompt('3번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x - length1 / 2, y: pointer.y - length3 / 2 },
+ { x: pointer.x - length1 / 2, y: pointer.y + length3 / 2 },
+ { x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 },
+ { x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 - length2 },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ const createTemplate7 = () => {
+ const length1 = Number(prompt('1번'))
+ const length2 = Number(prompt('2번'))
+ const length3 = Number(prompt('3번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x - length1 / 2, y: pointer.y - length2 / 2 },
+ { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 },
+ { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 },
+ { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 - length3 },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ const createTemplate8 = () => {
+ const length1 = Number(prompt('1번')) // 밑변
+ const length2 = Number(prompt('2번')) // 높이
+ const length3 = Number(prompt('3번')) // 빗변
+
+ const angleInRadians = Math.asin(length2 / length3)
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 },
+ { x: pointer.x - length1 / 2 + length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) },
+ { x: pointer.x + length1 / 2 + length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) },
+ { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ const createTemplate9 = () => {
+ const length1 = Number(prompt('1번')) // 밑변
+ const length2 = Number(prompt('2번')) // 높이
+ const length3 = Number(prompt('3번')) // 빗변
+
+ const angleInRadians = Math.asin(length2 / length3)
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 },
+ { x: pointer.x + length1 / 2 - length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) },
+ { x: pointer.x - length1 / 2 - length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) },
+ { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ const createTemplate10 = () => {
+ const length1 = Number(prompt('1번'))
+ const length2 = Number(prompt('2번'))
+ const length3 = Number(prompt('3번'))
+ const length4 = Number(prompt('4번'))
+ const length5 = Number(prompt('5번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x - (length1 + length2 + length3) / 2, y: pointer.y - (length4 + length5) / 2 },
+ { x: pointer.x - (length1 + length2 + length3) / 2, y: pointer.y + (length4 + length5) / 2 },
+ { x: pointer.x - (length1 + length2 + length3) / 2 + length1, y: pointer.y + (length4 + length5) / 2 },
+ { x: pointer.x - (length1 + length2 + length3) / 2 + length1, y: pointer.y + (length4 + length5) / 2 - length5 },
+ { x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2, y: pointer.y + (length4 + length5) / 2 - length5 },
+ { x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2, y: pointer.y + (length4 + length5) / 2 - length5 + length5 },
+ {
+ x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2 + length3,
+ y: pointer.y + (length4 + length5) / 2 - length5 + length5,
+ },
+ {
+ x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2 + length3,
+ y: pointer.y + (length4 + length5) / 2 - length5 + length5 - (length4 + length5),
+ },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ const createTemplate11 = () => {
+ const length1 = 200 //Number(prompt('1번'))
+ const length2 = 100 //Number(prompt('2번'))
+ const length3 = 400 //Number(prompt('3번'))
+ const length4 = 300 //Number(prompt('4번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 },
+ { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 },
+ { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length3 },
+ { x: pointer.x - length1 / 2 + length1 - (length1 - length2), y: pointer.y + length4 / 2 - length3 },
+ { x: pointer.x - length1 / 2 + length1 - (length1 - length2), y: pointer.y + length4 / 2 - length3 + (length3 - length4) },
+ { x: pointer.x - length1 / 2 + length1 - (length1 - length2) - length2, y: pointer.y + length4 / 2 - length3 + (length3 - length4) },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ const createTemplate12 = () => {
+ const length1 = 200 //Number(prompt('1번'))
+ const length2 = 100 //Number(prompt('2번'))
+ const length3 = 400 //Number(prompt('3번'))
+ const length4 = 300 //Number(prompt('4번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 },
+ { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 },
+ { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 },
+ { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length4 },
+ { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length4 - (length3 - length4) },
+ { x: pointer.x - length1 / 2 + length1 - length2 - (length1 - length2), y: pointer.y + length4 / 2 - length4 - (length3 - length4) },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ const createTemplate13 = () => {
+ const length1 = 300 //Number(prompt('1번'))
+ const length2 = 150 //Number(prompt('2번'))
+ const length3 = 100 //Number(prompt('3번'))
+ const length4 = 400 //Number(prompt('4번'))
+ const length5 = 200 //Number(prompt('5번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 },
+ { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 },
+ { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 },
+ { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 },
+ { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 + (length4 - length5) },
+ { x: pointer.x - length1 / 2 + length1 - length3 - length2, y: pointer.y + length4 / 2 - length4 + (length4 - length5) },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ const createTemplate14 = () => {
+ const length1 = 300 //Number(prompt('1번'))
+ const length2 = 150 //Number(prompt('2번'))
+ const length3 = 100 //Number(prompt('3번'))
+ const length4 = 400 //Number(prompt('4번'))
+ const length5 = 200 //Number(prompt('5번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x + length1 / 2, y: pointer.y + length4 / 2 },
+ { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 },
+ { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length4 },
+ { x: pointer.x + length1 / 2 - length1 + length3, y: pointer.y + length4 / 2 - length4 },
+ { x: pointer.x + length1 / 2 - length1 + length3, y: pointer.y + length4 / 2 - length4 + (length4 - length5) },
+ { x: pointer.x + length1 / 2 - length1 + length3 + length2, y: pointer.y + length4 / 2 - length4 + (length4 - length5) },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ const createTemplate15 = () => {
+ const length1 = 300 //Number(prompt('1번'))
+ const length2 = 150 //Number(prompt('2번'))
+ const length3 = 100 //Number(prompt('3번'))
+ const length4 = 400 //Number(prompt('4번'))
+ const length5 = 200 //Number(prompt('5번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x + length1 / 2, y: pointer.y + length4 / 2 },
+ { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 },
+ { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length5 },
+ { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 },
+ { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) },
+ { x: pointer.x + length1 / 2 - length1 + length2 + length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ const createTemplate16 = () => {
+ const length1 = 300 //Number(prompt('1번'))
+ const length2 = 150 //Number(prompt('2번'))
+ const length3 = 100 //Number(prompt('3번'))
+ const length4 = 400 //Number(prompt('4번'))
+ const length5 = 200 //Number(prompt('5번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 },
+ { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 },
+ { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length5 },
+ { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 },
+ { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) },
+ { x: pointer.x - length1 / 2 + length1 - length2 - length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ const createTemplate17 = () => {
+ const length1 = 300 //Number(prompt('1번'))
+ const length2 = 150 //Number(prompt('2번'))
+ const length3 = 250 //Number(prompt('3번'))
+ const length4 = 400 //Number(prompt('4번'))
+ const length5 = 200 //Number(prompt('5번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 },
+ { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 },
+ { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length5 },
+ { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 },
+ { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) },
+ { x: pointer.x - length1 / 2 + length1 - length2 - length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ const createTemplate18 = () => {
+ const length1 = 300 //Number(prompt('1번'))
+ const length2 = 150 //Number(prompt('2번'))
+ const length3 = 250 //Number(prompt('3번'))
+ const length4 = 400 //Number(prompt('4번'))
+ const length5 = 200 //Number(prompt('5번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x + length1 / 2, y: pointer.y + length4 / 2 },
+ { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 },
+ { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length5 },
+ { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 },
+ { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) },
+ { x: pointer.x + length1 / 2 - length1 + length2 + length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ /**
+ * 19~22번은 못함
+ */
+ const createTemplate23 = () => {
+ const length1 = 300 //Number(prompt('1번'))
+ const length2 = 100 //Number(prompt('2번'))
+ const length3 = 150 //Number(prompt('3번'))
+ const length4 = 400 //Number(prompt('4번'))
+ const length5 = 300 //Number(prompt('5번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x - length1 / 2 + length2, y: pointer.y + length4 / 2 },
+ { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 },
+ { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 - length4 },
+ { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 },
+ { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 + length4 },
+ { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 + length4 },
+ { x: pointer.x - length1 / 2 + length2 + (length1 - length2 - length3) / 2, y: pointer.y + length4 / 2 - length4 + length5 },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+
+ const createTemplate24 = () => {
+ const length1 = 300 //Number(prompt('1번'))
+ const length2 = 400 //Number(prompt('2번'))
+ const length3 = 300 //Number(prompt('3번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ { x: pointer.x - length1 / 2, y: pointer.y + length2 - length2 / 2 },
+ { x: pointer.x - length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 },
+ { x: pointer.x, y: pointer.y + length2 - length2 / 2 - length3 - (length2 - length3) },
+ { x: pointer.x + length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 },
+ { x: pointer.x + length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 + length3 },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ const createTemplate25 = () => {
+ const length1 = 300 //Number(prompt('1번'))
+ const length2 = 200 //Number(prompt('2번'))
+ const length3 = 300 //Number(prompt('3번'))
+ const length4 = 200 //Number(prompt('3번'))
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ {
+ x: pointer.x - length1 / 2,
+ y: pointer.y + length3 / 2,
+ },
+ {
+ x: pointer.x - length1 / 2 + (length1 - length2) / 2,
+ y: pointer.y + length3 / 2 - (length3 - length4),
+ },
+ {
+ x: pointer.x - length1 / 2 + (length1 - length2) / 2,
+ y: pointer.y + length3 / 2 - (length3 - length4) - length4,
+ },
+ {
+ x: pointer.x - length1 / 2 + (length1 - length2) / 2 + length2,
+ y: pointer.y + length3 / 2 - (length3 - length4) - length4,
+ },
+ {
+ x: pointer.x - length1 / 2 + (length1 - length2) / 2 + length2,
+ y: pointer.y + length3 / 2 - (length3 - length4) - length4 + length4,
+ },
+ {
+ x: pointer.x - length1 / 2 + length1,
+ y: pointer.y + length3 / 2,
+ },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ const createTemplate26 = () => {
+ const length1 = 500 //Number(prompt('1번'))
+ const length2 = 200 //Number(prompt('2번'))
+ const length3 = 300 //Number(prompt('3번'))
+ const length4 = 400 //Number(prompt('3번'))
+
+ const angle = (Math.asin(length3 / length4) * 180) / Math.PI // 높이와 빗변으로 먼저 각도구하기
+
+ const topL = (length1 - length2) / 2 / Math.cos((angle * Math.PI) / 180) // 꺽이는부분 윗쪽 길이
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ {
+ x: pointer.x - length1 / 2 + length1,
+ y: pointer.y + length3 / 2,
+ },
+ {
+ x: pointer.x - length1 / 2,
+ y: pointer.y + length3 / 2,
+ },
+ {
+ x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)),
+ y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)),
+ },
+ {
+ x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)) + length2,
+ y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)),
+ },
+ {
+ x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)) + length2 + topL * Math.cos(degreesToRadians(angle)),
+ y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)) + topL * Math.sin(degreesToRadians(angle)),
+ },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ const createTemplate27 = () => {
+ const length1 = 500 //Number(prompt('1번'))
+ const length2 = 200 //Number(prompt('2번'))
+ const length3 = 300 //Number(prompt('3번'))
+ const length4 = 400 //Number(prompt('3번'))
+
+ const angle = (Math.asin(length3 / length4) * 180) / Math.PI // 높이와 빗변으로 먼저 각도구하기
+
+ const topL = (length1 - length2) / 2 / Math.cos((angle * Math.PI) / 180) // 꺽이는부분 윗쪽 길이
+
+ let isDrawing = true
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const triangle = new QPolygon(
+ [
+ {
+ x: pointer.x - length1 / 2,
+ y: pointer.y + length3 / 2,
+ },
+ {
+ x: pointer.x - length1 / 2 + length1,
+ y: pointer.y + length3 / 2,
+ },
+ {
+ x: pointer.x - length1 / 2 + length1 - length4 * Math.cos(degreesToRadians(angle)),
+ y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)),
+ },
+ {
+ x: pointer.x - length1 / 2 + length1 - length4 * Math.cos(degreesToRadians(angle)) - length2,
+ y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)),
+ },
+ {
+ x: pointer.x - length1 / 2 + length1 - length4 * Math.cos(degreesToRadians(angle)) - length2 - topL * Math.cos(degreesToRadians(angle)),
+ y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)) + topL * Math.sin(degreesToRadians(angle)),
+ },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(triangle)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ })
+ }
+ const createTemplate28 = () => {
+ const length1 = Number(prompt('밑변'))
+ const length2 = Number(prompt('높이'))
+ const length3 = Number(prompt('빗변'))
+
+ const a = Math.sqrt(length3 * length3 - length2 * length2) // 입력된 밑변과 높이
+
+ const sinA = a / length3
+ const angleInRadians = Math.asin(sinA)
+ const angleInDegrees = angleInRadians * (180 / Math.PI)
+ const b = a - length1 / 2
+
+ const c = b / Math.tan(angleInRadians)
+ const d = Math.sqrt(b * b + c * c)
+
+ if (isNaN(a)) {
+ alert('값이 잘못되었습니다.')
+ return
+ }
+ if (b < 0) {
+ alert('값이 잘못되었습니다.')
+ return
+ }
+ if (angleInDegrees === 0 || angleInRadians === 0) {
+ alert('값이 잘못되었습니다.')
+ return
+ }
+
+ let isDrawing = true
+ let pentagon
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const newAngleInRadians = (90 - angleInDegrees) * (Math.PI / 180)
+
+ pentagon = new QPolygon(
+ [
+ { x: pointer.x - (length1 + b) / 2, y: pointer.y + length2 / 2 },
+ { x: pointer.x + length1 / 2 - b / 2, y: pointer.y + length2 / 2 },
+ {
+ x: pointer.x + length1 / 2 - b / 2 + d * Math.cos(newAngleInRadians),
+ y: pointer.y + length2 / 2 - d * Math.sin(newAngleInRadians),
+ },
+ {
+ x: pointer.x - (length1 + b) / 2 + length3 * Math.cos(newAngleInRadians),
+ y: pointer.y + length2 / 2 - length3 * Math.sin(newAngleInRadians),
+ },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'gray',
+ strokeWidth: 1,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(pentagon)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ pentagon.set('name', 'roof')
+ pentagon.set('stroke', 2)
+ canvas?.renderAll()
+ })
+ }
+ const createTemplate29 = () => {
+ const length1 = Number(prompt('밑변'))
+ const length2 = Number(prompt('높이'))
+ const length3 = Number(prompt('빗변'))
+
+ const a = Math.sqrt(length3 * length3 - length2 * length2) // 입력된 밑변과 높이
+
+ const sinA = a / length3
+ const angleInRadians = Math.asin(sinA)
+ const angleInDegrees = angleInRadians * (180 / Math.PI)
+ const b = a - length1 / 2
+
+ const c = b / Math.tan(angleInRadians)
+ const d = Math.sqrt(b * b + c * c)
+
+ if (isNaN(a)) {
+ alert('값이 잘못되었습니다.')
+ return
+ }
+ if (b < 0) {
+ alert('값이 잘못되었습니다.')
+ return
+ }
+ if (angleInDegrees === 0 || angleInRadians === 0) {
+ alert('값이 잘못되었습니다.')
+ return
+ }
+
+ let isDrawing = true
+ let pentagon
+ canvas?.on('mouse:move', (e) => {
+ if (!isDrawing) {
+ return
+ }
+ canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle'))
+ const pointer = canvas?.getPointer(e.e)
+ const newAngleInRadians = (90 - angleInDegrees) * (Math.PI / 180)
+
+ pentagon = new QPolygon(
+ [
+ {
+ x: pointer.x + length1 / 2 - b / 2 - length3 * Math.cos(newAngleInRadians),
+ y: pointer.y + length2 / 2 - length3 * Math.sin(newAngleInRadians),
+ },
+ { x: pointer.x + length1 / 2 - b / 2, y: pointer.y + length2 / 2 },
+ { x: pointer.x - (length1 + b) / 2, y: pointer.y + length2 / 2 },
+ { x: pointer.x - (length1 + b) / 2 - d * Math.cos(newAngleInRadians), y: pointer.y + length2 / 2 - d * Math.sin(newAngleInRadians) },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'gray',
+ strokeWidth: 1,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'guideTriangle',
+ },
+ )
+
+ canvas?.add(pentagon)
+ })
+
+ canvas?.on('mouse:down', (e) => {
+ isDrawing = false
+ pentagon.set('name', 'roof')
+ pentagon.set('stroke', 2)
+ canvas?.renderAll()
+ })
+ }
+
return (
<>
{canvas && (
@@ -728,6 +1874,84 @@ export default function Roof2(props) {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/Settings.jsx b/src/components/Settings.jsx
new file mode 100644
index 00000000..2d8eaeda
--- /dev/null
+++ b/src/components/Settings.jsx
@@ -0,0 +1,197 @@
+'use client'
+
+import React, { useEffect, useState } from 'react';
+import { Button } from '@nextui-org/react';
+
+import { get, post } from '@/lib/Axios';
+
+export default function Settings() {
+ const [objectNo, setObjectNo] = useState('test123240829010');
+ const [error, setError] = useState(null);
+
+ // 상태를 하나의 객체로 관리
+ const [settings, setSettings] = useState({
+ display1: Array(11).fill('N'), // 화면 표시1
+ display2: Array(3).fill('N'), // 화면 표시2
+ rangeSetting: 0, // 흡착 범위 설정
+ gridSettings: [] // 그리드 설정
+ });
+
+ const gridItems = {
+ display1: [
+ '할당 표시', '도면 표시', '그리드 표시', '문자 표시', '흐름방향 표시',
+ '복도치수 표시', '실제치수 표시', '치수 표시 없음', '가대 표시',
+ '좌표 표시', '도면전환 표시'
+ ],
+ display2: ['테두리만', '라인해치', 'All Painted'],
+ rangeSetting: ['극소', '소', '중', '대'],
+ gridSettings: ['임의 그리드', '실선 그리드', '점 그리드', '그리드 색 설정', '흡착점 추가']
+ };
+
+ // 클릭 시 상태 변경 함수
+ const handleToggle = (type, index) => {
+
+ setSettings((prevSettings) => {
+
+ // prevSettings[type]이 배열인지 확인하고, 그렇지 않은 경우 빈 배열로 초기화
+ let updated = Array.isArray(prevSettings[type]) ? [...prevSettings[type]] : [];
+
+ if (type === 'rangeSetting') {
+ return { ...prevSettings, [type]: index };
+ }
+
+ updated[index] = updated[index] === 'N' ? 'Y' : 'N';
+ return { ...prevSettings, [type]: updated };
+ });
+ };
+
+ // Canvas Setting 조회 및 초기화
+ const handleSelect = async () => {
+ try {
+ const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` });
+
+ // 데이터가 없는 경우
+ if (!res || res.length === 0) {
+
+ console.warn('조회 결과가 없습니다.');
+ // 기본값을 설정하거나 사용자에게 알림 표시
+ setSettings({
+ display1: Array(11).fill('N'), // 화면 표시1 기본값
+ display2: Array(3).fill('N'), // 화면 표시2 기본값
+ rangeSetting: 0, // 흡착 범위 설정 기본값
+ gridSettings: [] // 그리드 설정 초기화
+ });
+
+ alert('조회된 데이터가 없습니다. 기본 설정이 적용됩니다.');
+ return; // 이후 코드 실행을 중단
+ }
+
+ const data = res.map((item) => ({
+ display1: [
+ item.assignDisplay, item.drawDisplay, item.gridDisplay, item.charDisplay, item.flowDisplay,
+ item.hallwayDimenDisplay, item.actualDimenDisplay, item.noDimenDisplay, item.trestleDisplay,
+ item.coordiDisplay, item.drawConverDisplay
+ ],
+ display2: [item.onlyBorder, item.lineHatch, item.allPainted],
+ rangeSetting: Number(item.adsorpRangeSetting)
+ }));
+
+ setSettings({
+ display1: data[0].display1,
+ display2: data[0].display2,
+ rangeSetting: data[0].rangeSetting,
+ gridSettings: [] // 초기화
+ });
+ } catch (error) {
+ console.error('Data fetching error:', error);
+ }
+ };
+
+ // Canvas Setting 저장
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+
+ if (!objectNo) {
+ alert('object_no를 입력하세요.');
+ return;
+ }
+
+ const patternData = {
+ objectNo,
+ assignDisplay: settings.display1[0],
+ drawDisplay: settings.display1[1],
+ gridDisplay: settings.display1[2],
+ charDisplay: settings.display1[3],
+ flowDisplay: settings.display1[4],
+ hallwayDimenDisplay: settings.display1[5],
+ actualDimenDisplay: settings.display1[6],
+ noDimenDisplay: settings.display1[7],
+ trestleDisplay: settings.display1[8],
+ coordiDisplay: settings.display1[9],
+ drawConverDisplay: settings.display1[10],
+ onlyBorder: settings.display2[0],
+ lineHatch: settings.display2[1],
+ allPainted: settings.display2[2],
+ adsorpRangeSetting: String(settings.rangeSetting)
+ };
+
+ await post({ url: `/api/canvas-management/canvas-settings`, data: patternData });
+
+ // 저장 후 재조회
+ handleSelect();
+ };
+
+ // 초기 조회
+ useEffect(() => {
+ if (objectNo) {
+ handleSelect(objectNo);
+ } else {
+ alert('object_no를 입력하세요.');
+ }
+ }, []);
+
+ return (
+ <>
+
+
+ setObjectNo(e.target.value)} />
+
+
+
+
+
[디스플레이 설정]
+
* 도면에 표시할 항목을 클릭하면 적용 됩니다.
+
+ {gridItems.display1.map((item, index) => (
+
handleToggle('display1', index)}
+ >
+ {settings.display1[index]} {item}
+
+ ))}
+
+
+
* 화면 표시
+
+ {gridItems.display2.map((item, index) => (
+
handleToggle('display2', index)}
+ >
+ {settings.display2[index]} {item}
+
+ ))}
+
+
[글꼴/도면크기 설정]
+
* 흡착 범위 설정
+
+ {gridItems.rangeSetting.map((item, index) => (
+
handleToggle('rangeSetting', index)}
+ >
+ {settings.rangeSetting === index ? 'Y' : 'N'} {item}
+
+ ))}
+
+
[그리드 설정]
+
+ {gridItems.gridSettings.map((item, index) => (
+
handleToggle('gridSettings', index)}
+ >
+ {settings.gridSettings.includes(index) ? 'Y' : 'N'} {item}
+
+ ))}
+
+
+
+ >
+ );
+}
\ No newline at end of file
diff --git a/src/components/fabric/HelpLine.js b/src/components/fabric/HelpLine.js
deleted file mode 100644
index 68112099..00000000
--- a/src/components/fabric/HelpLine.js
+++ /dev/null
@@ -1,108 +0,0 @@
-import { fabric } from 'fabric'
-
-export class QLine extends fabric.Group {
- line
- text
- fontSize
- length = 0
- x1
- y1
- x2
- y2
- direction
- type = 'HelpLine'
- parent
- #lengthTxt = 0
-
- constructor(points, option, lengthTxt) {
- const [x1, y1, x2, y2] = points
-
- if (!option.fontSize) {
- throw new Error('Font size is required.')
- }
-
- const line = new fabric.Line(points, { ...option, strokeWidth: 1 })
- super([line], {})
-
- this.x1 = x1
- this.y1 = y1
- this.x2 = x2
- this.y2 = y2
- this.line = line
- this.fontSize = option.fontSize
- this.direction = option.direction
- this.parent = option.parent
-
- if (lengthTxt > 0) {
- this.#lengthTxt = Number(lengthTxt)
- }
-
- this.#init()
- this.#addControl()
- }
-
- #init() {
- this.#addLengthText(true)
- }
-
- #addControl() {
- this.on('moving', () => {
- this.#addLengthText(false)
- })
-
- this.on('modified', (e) => {
- this.#addLengthText(false)
- })
-
- this.on('selected', () => {
- Object.keys(this.controls).forEach((controlKey) => {
- if (controlKey !== 'ml' && controlKey !== 'mr') {
- this.setControlVisible(controlKey, false)
- }
- })
- })
- }
-
- #addLengthText(isFirst) {
- if (this.text) {
- this.removeWithUpdate(this.text)
- this.text = null
- }
-
- if (isFirst && this.#lengthTxt > 0) {
- const text = new fabric.Textbox(this.#lengthTxt.toFixed(0).toString(), {
- left: (this.x1 + this.x2) / 2,
- top: (this.y1 + this.y2) / 2,
- fontSize: this.fontSize,
- })
- this.length = this.#lengthTxt
- this.text = text
- this.addWithUpdate(text)
- return
- }
-
- const scaleX = this.scaleX
- const scaleY = this.scaleY
- const x1 = this.left
- const y1 = this.top
- const x2 = this.left + this.width * scaleX
- const y2 = this.top + this.height * scaleY
- const dx = x2 - x1
- const dy = y2 - y1
- this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0))
-
- const text = new fabric.Textbox(this.length.toFixed(0).toString(), {
- left: (x1 + x2) / 2,
- top: (y1 + y2) / 2,
- fontSize: this.fontSize,
- })
- this.text = text
- this.addWithUpdate(text)
- }
-
- setFontSize(fontSize) {
- this.fontSize = fontSize
- this.text.set({ fontSize })
- this.addWithUpdate()
- }
-}
diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js
index c5093f91..c6da782f 100644
--- a/src/components/fabric/QPolygon.js
+++ b/src/components/fabric/QPolygon.js
@@ -18,6 +18,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
parentId: null,
innerLines: [],
children: [],
+ initOptions: null,
initialize: function (points, options, canvas) {
// 소수점 전부 제거
points.forEach((point) => {
@@ -58,6 +59,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
this.canvas = canvas
}
+ this.initOptions = options
+
this.init()
this.initLines()
this.setShape()
@@ -177,7 +180,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
const degree = (Math.atan2(dy, dx) * 180) / Math.PI
// Create new text object if it doesn't exist
- const text = new fabric.Text(length.toFixed(0), {
+ const text = new fabric.IText(length.toFixed(0), {
left: midPoint.x,
top: midPoint.y,
fontSize: this.fontSize,
@@ -189,7 +192,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
parentDirection: getDirectionByPoint(start, end),
parentDegree: degree,
dirty: true,
- editable: false,
+ editable: true,
selectable: true,
lockRotation: true,
lockScalingX: true,
diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js
index bcc8b7d7..0dc724f3 100644
--- a/src/hooks/useCanvas.js
+++ b/src/hooks/useCanvas.js
@@ -425,6 +425,8 @@ export function useCanvas(id) {
'maxY',
'minX',
'minY',
+ 'x',
+ 'y',
])
const str = JSON.stringify(objs)
diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js
index 89a15b3a..e5582733 100644
--- a/src/hooks/useCanvasEvent.js
+++ b/src/hooks/useCanvasEvent.js
@@ -2,6 +2,7 @@ import { useEffect, useState } from 'react'
import { fabric } from 'fabric'
import { useRecoilState, useRecoilValue } from 'recoil'
import { canvasSizeState, currentObjectState, modeState } from '@/store/canvasAtom'
+import { QPolygon } from '@/components/fabric/QPolygon'
// 캔버스에 필요한 이벤트
export function useCanvasEvent() {
@@ -19,9 +20,9 @@ export function useCanvasEvent() {
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)
- })
+ })*/
canvas?.on('object:removed', objectEvent.removed)
}
@@ -77,11 +78,55 @@ export function useCanvasEvent() {
if (target.name === 'lengthText') {
const x = target.left
const y = target.top
+ // Add a property to store the previous value
+ const previousValue = target.text
target.on('selected', (e) => {
Object.keys(target.controls).forEach((controlKey) => {
target.setControlVisible(controlKey, false)
})
})
+ target.on('editing:exited', () => {
+ if (isNaN(target.text.trim())) {
+ target.set({ text: previousValue })
+ canvas?.renderAll()
+ return
+ }
+ const updatedValue = parseFloat(target.text.trim())
+ const targetParent = target.parent
+ const points = targetParent.getCurrentPoints()
+ const i = target.idx // Assuming target.index gives the index of the point
+
+ const startPoint = points[i]
+ const endPoint = points[(i + 1) % points.length]
+
+ const dx = endPoint.x - startPoint.x
+ const dy = endPoint.y - startPoint.y
+
+ const currentLength = Math.sqrt(dx * dx + dy * dy)
+ const scaleFactor = updatedValue / currentLength
+
+ const newEndPoint = {
+ x: startPoint.x + dx * scaleFactor,
+ y: startPoint.y + dy * scaleFactor,
+ }
+
+ const newPoints = [...points]
+ newPoints[(i + 1) % points.length] = newEndPoint
+
+ for (let idx = i + 1; idx < points.length; idx++) {
+ if (newPoints[idx].x === endPoint.x) {
+ newPoints[idx].x = newEndPoint.x
+ } else if (newPoints[idx].y === endPoint.y) {
+ newPoints[idx].y = newEndPoint.y
+ }
+ }
+
+ const newPolygon = new QPolygon(newPoints, targetParent.initOptions)
+ canvas?.add(newPolygon)
+ canvas?.remove(targetParent)
+ canvas?.renderAll()
+ })
+
target.on('moving', (e) => {
if (target.parentDirection === 'left' || target.parentDirection === 'right') {
const minX = target.minX
@@ -116,7 +161,6 @@ export function useCanvasEvent() {
if (whiteList.includes(e.target.name)) {
return
}
- console.log('removed', e)
},
}
diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js
index ae970461..b6c4680d 100644
--- a/src/hooks/useMode.js
+++ b/src/hooks/useMode.js
@@ -1,4 +1,4 @@
-import { useEffect, useRef, useState } from 'react'
+import { useCallback, useEffect, useRef, useState } from 'react'
import {
calculateIntersection,
distanceBetweenPoints,
@@ -25,6 +25,8 @@ import {
templateTypeState,
wallState,
guideLineState,
+ horiGuideLinesState,
+ vertGuideLinesState,
} from '@/store/canvasAtom'
import { QLine } from '@/components/fabric/QLine'
import { fabric } from 'fabric'
@@ -64,23 +66,22 @@ export function useMode() {
const compass = useRecoilValue(compassState)
const [isCellCenter, setIsCellCenter] = useState(false)
- const guideLineInfo = useRecoilValue(guideLineState)
+ const [guideLineInfo, setGuideLineInfo] = useRecoilState(guideLineState)
const [guideLineMode, setGuideLineMode] = useState(false)
const [guideDotMode, setGuideDotMode] = useState(false)
+ const [horiGuideLines, setHoriGuideLines] = useRecoilState(horiGuideLinesState)
+ const [vertGuideLines, setVertGuideLines] = useRecoilState(vertGuideLinesState)
+
useEffect(() => {
- // 이벤트 리스너 추가
// if (!canvas) {
// canvas?.setZoom(0.8)
// return
// }
- document.addEventListener('keydown', handleKeyDown)
+ if (!canvas) return
+ setCanvas(canvas)
canvas?.on('mouse:move', drawMouseLines)
- // 컴포넌트가 언마운트될 때 이벤트 리스너 제거
- return () => {
- document.removeEventListener('keydown', handleKeyDown)
- }
}, [canvas]) // 빈 배열을 전달하여 컴포넌트가 마운트될 때만 실행되도록 함
useEffect(() => {
@@ -100,15 +101,12 @@ export function useMode() {
}, [endPoint])
useEffect(() => {
+ canvas?.off('mouse:out', removeMouseLines)
+ canvas?.on('mouse:out', removeMouseLines)
+ changeMode(canvas, mode)
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])
+ }, [mode, horiGuideLines, vertGuideLines])
useEffect(() => {
setGuideLineMode(false)
@@ -142,8 +140,8 @@ export function useMode() {
}
if (isGuideLineMode) {
- horizontalLineArray = [...guideLineState[0].horizontalLineArray]
- verticalLineArray = [...guideLineState[0].verticalLineArray]
+ horizontalLineArray = [...horiGuideLines]
+ verticalLineArray = [...vertGuideLines]
guideLineLengthHori = Number(guideLineState[0].moduleHoriLength)
guideLineLengthVert = Number(guideLineState[0].moduleVertLength)
}
@@ -163,12 +161,27 @@ export function useMode() {
if (mode === Mode.EDIT || mode === Mode.ADSORPTION_POINT) {
let adsorptionPoint = adsorptionPointList.length > 0 ? findClosestPoint(pointer, adsorptionPointList) : null
+ if ((horiGuideLines.length > 0 || vertGuideLines.length > 0) && guideDotMode) {
+ const closestHorizontalLine = getClosestHorizontalLine(pointer, horiGuideLines)
+ const closetVerticalLine = getClosestVerticalLine(pointer, vertGuideLines)
+ let intersection = null
+ let intersectionDistance = Infinity
- 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 (closestHorizontalLine && closetVerticalLine) {
+ intersection = calculateIntersection(closestHorizontalLine, closetVerticalLine)
+ if (intersection) {
+ intersectionDistance = distanceBetweenPoints(pointer, intersection)
+ }
+ }
+
+ let xDiff, yDiff
+
+ if (closetVerticalLine) {
+ xDiff = Math.abs(pointer.x - closetVerticalLine.x1)
+ }
+ if (closestHorizontalLine) {
+ 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)
@@ -177,22 +190,26 @@ export function useMode() {
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 (intersection && intersectionDistance < 20) {
+ newX = intersection.x
+ newY = intersection.y
+ } 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) {
+ } else if (guideDotMode) {
const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori)
const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert)
@@ -205,11 +222,27 @@ export function useMode() {
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)
+ } else if (horiGuideLines.length > 0 || vertGuideLines.length > 0) {
+ const closestHorizontalLine = getClosestHorizontalLine(pointer, horiGuideLines)
+ const closetVerticalLine = getClosestVerticalLine(pointer, vertGuideLines)
+ let intersection = null
+ let intersectionDistance = Infinity
+
+ if (closestHorizontalLine && closetVerticalLine) {
+ intersection = calculateIntersection(closestHorizontalLine, closetVerticalLine)
+ if (intersection) {
+ intersectionDistance = distanceBetweenPoints(pointer, intersection)
+ }
+ }
+
+ let xDiff, yDiff
+
+ if (closetVerticalLine) {
+ xDiff = Math.abs(pointer.x - closetVerticalLine.x1)
+ }
+ if (closestHorizontalLine) {
+ 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)
@@ -218,23 +251,26 @@ export function useMode() {
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 (intersection && intersectionDistance < 20) {
+ newX = intersection.x
+ newY = intersection.y
+ } 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
@@ -362,16 +398,13 @@ export function useMode() {
// 모드에 따른 마우스 이벤트 변경
const changeMouseEvent = (mode) => {
- canvas?.off('mouse:down')
switch (mode) {
case 'drawLine':
canvas?.on('mouse:down', mouseEvent.drawLineModeLeftClick)
- window.document.removeEventListener('contextmenu', mouseEvent.drawLineModeRightClick)
- window.document.addEventListener('contextmenu', mouseEvent.drawLineModeRightClick)
+ document.addEventListener('contextmenu', mouseEvent.drawLineModeRightClick)
break
case 'edit':
canvas?.on('mouse:down', mouseEvent.editMode)
-
break
case 'textbox':
canvas?.on('mouse:down', mouseEvent.textboxMode)
@@ -394,9 +427,6 @@ export function useMode() {
}
}
- // 모드에 따른 키보드 이벤트 변경
- const changeKeyboardEvent = (mode) => {}
-
const keyValid = () => {
if (points.current.length === 0) {
alert('시작점을 선택해주세요')
@@ -552,77 +582,98 @@ export function useMode() {
}
}
- const handleKeyDown = (e) => {
- switch (e.key) {
- case 'ArrowDown': {
- if (!keyValid()) {
- return
- }
- const verticalLength = Number(prompt('길이를 입력하세요:'))
- const horizontalLength = 0
+ const mouseAndkeyboardEventClear = () => {
+ canvas?.off('mouse:down')
+ Object.keys(mouseEvent).forEach((key) => {
+ canvas?.off('mouse:down', mouseEvent[key])
+ document.removeEventListener('contextmenu', mouseEvent[key])
+ })
- drawCircleAndLine(verticalLength, horizontalLength)
+ Object.keys(keyboardEvent).forEach((key) => {
+ document.removeEventListener('keydown', keyboardEvent[key])
+ })
+ }
- break
- }
- case 'ArrowUp': {
- if (!keyValid()) {
- return
- }
- const verticalLength = -Number(prompt('길이를 입력하세요:'))
- const horizontalLength = 0
+ const keyboardEvent = {
+ // rerendering을 막기 위해 useCallback 사용
+ editMode: useCallback(
+ (e) => {
+ e.preventDefault()
+ switch (e.key) {
+ case 'ArrowDown': {
+ if (!keyValid()) {
+ return
+ }
+ const verticalLength = Number(prompt('길이를 입력하세요:'))
+ const horizontalLength = 0
- drawCircleAndLine(verticalLength, horizontalLength)
+ drawCircleAndLine(verticalLength, horizontalLength)
- break
- }
- case 'ArrowLeft': {
- if (!keyValid()) {
- return
- }
- const verticalLength = 0
- const horizontalLength = -Number(prompt('길이를 입력하세요:'))
-
- drawCircleAndLine(verticalLength, horizontalLength)
-
- break
- }
- case 'ArrowRight': {
- if (!keyValid()) {
- return
- }
-
- const verticalLength = 0
- const horizontalLength = Number(prompt('길이를 입력하세요:'))
-
- drawCircleAndLine(verticalLength, horizontalLength)
-
- break
- }
-
- case 'Enter': {
- const result = prompt('입력하세요 (a(A패턴),b(B패턴),t(지붕))')
-
- switch (result) {
- case 'a':
- applyTemplateA()
break
- case 'b':
- applyTemplateB()
+ }
+ case 'ArrowUp': {
+ if (!keyValid()) {
+ return
+ }
+ const verticalLength = -Number(prompt('길이를 입력하세요:'))
+ const horizontalLength = 0
+
+ drawCircleAndLine(verticalLength, horizontalLength)
+
break
- case 't':
- templateMode()
+ }
+ case 'ArrowLeft': {
+ if (!keyValid()) {
+ return
+ }
+ const verticalLength = 0
+ const horizontalLength = -Number(prompt('길이를 입력하세요:'))
+
+ drawCircleAndLine(verticalLength, horizontalLength)
+
break
+ }
+ case 'ArrowRight': {
+ if (!keyValid()) {
+ return
+ }
+
+ const verticalLength = 0
+ const horizontalLength = Number(prompt('길이를 입력하세요:'))
+
+ drawCircleAndLine(verticalLength, horizontalLength)
+
+ break
+ }
+
+ case 'Enter': {
+ const result = prompt('입력하세요 (a(A패턴),b(B패턴),t(지붕))')
+
+ switch (result) {
+ case 'a':
+ applyTemplateA()
+ break
+ case 'b':
+ applyTemplateB()
+ break
+ case 't':
+ templateMode()
+ break
+ }
+ }
}
- }
- }
+ },
+ [canvas],
+ ),
}
const changeMode = (canvas, mode) => {
+ mouseAndkeyboardEventClear()
setMode(mode)
setCanvas(canvas)
// mode별 이벤트 변경
+
changeMouseEvent(mode)
changeKeyboardEvent(mode)
@@ -657,40 +708,82 @@ export function useMode() {
}
}
+ const changeKeyboardEvent = (mode) => {
+ if (mode === Mode.EDIT) {
+ switch (mode) {
+ case 'edit':
+ document.addEventListener('keydown', keyboardEvent.editMode)
+ break
+ }
+ }
+ }
+
const mouseEvent = {
drawLineModeLeftClick: (options) => {
+ if (mode !== Mode.DRAW_LINE) {
+ return
+ }
const pointer = canvas?.getPointer(options.e)
const line = new QLine(
- [pointer.x, 0, pointer.x, canvas.height], // y축에 1자 선을 그립니다.
+ [pointer.x, 0, pointer.x, canvasSize.vertical], // y축에 1자 선을 그립니다.
{
- stroke: 'black',
- strokeWidth: 2,
- viewLengthText: true,
- selectable: false,
- fontSize: fontSize,
+ stroke: 'gray',
+ strokeWidth: 1,
+ selectable: true,
+ lockMovementX: true,
+ lockMovementY: true,
+ lockRotation: true,
+ lockScalingX: true,
+ lockScalingY: true,
+ name: 'guideLine',
+ direction: 'vertical',
},
)
canvas?.add(line)
canvas?.renderAll()
- },
- drawLineModeRightClick: (options) => {
- const line = new fabric.Line(
- [0, options.offsetY, canvas.width, options.offsetY], // y축에 1자 선을 그립니다.
- {
- stroke: 'black',
- strokeWidth: 2,
- viewLengthText: true,
- selectable: false,
- fontSize: fontSize,
- },
- )
- canvas?.add(line)
- canvas?.renderAll()
+ const newVerticalLineArray = [...vertGuideLines]
+ newVerticalLineArray.push(line)
+
+ setVertGuideLines(newVerticalLineArray)
},
+ drawLineModeRightClick: useCallback(
+ (options) => {
+ document.removeEventListener('contextmenu', mouseEvent.drawLineModeRightClick)
+ if (mode !== Mode.DRAW_LINE) {
+ return
+ }
+ const line = new fabric.Line(
+ [0, options.offsetY, canvasSize.horizontal, options.offsetY], // y축에 1자 선을 그립니다.
+ {
+ stroke: 'gray',
+ strokeWidth: 1,
+ selectable: true,
+ lockMovementX: true,
+ lockMovementY: true,
+ lockRotation: true,
+ lockScalingX: true,
+ lockScalingY: true,
+ name: 'guideLine',
+ direction: 'horizontal',
+ },
+ )
+
+ canvas?.add(line)
+ canvas?.renderAll()
+
+ const newHorizontalLineArray = [...horiGuideLines]
+ newHorizontalLineArray.push(line)
+ setHoriGuideLines(newHorizontalLineArray)
+ },
+ [canvas, mode, horiGuideLines],
+ ),
editMode: (options) => {
+ if (mode !== Mode.EDIT) {
+ return
+ }
let pointer = canvas?.getPointer(options.e)
if (getInterSectPointByMouseLine()) {
@@ -801,7 +894,9 @@ export function useMode() {
canvas?.renderAll()
},
+
textboxMode: (options) => {
+ if (mode !== Mode.TEXTBOX) return
if (canvas?.getActiveObject()?.type === 'textbox') return
const pointer = canvas?.getPointer(options.e)
@@ -821,6 +916,7 @@ export function useMode() {
})
},
drawRectMode: (o) => {
+ if (mode !== Mode.DRAW_RECT) return
let rect, isDown, origX, origY
isDown = true
const pointer = canvas.getPointer(o.e)
@@ -862,7 +958,8 @@ export function useMode() {
})
},
// 흡착점 추가
- adsorptionPoint(o) {
+ adsorptionPoint: (o) => {
+ if (mode !== Mode.ADSORPTION_POINT) return
const pointer = canvas.getPointer(o.e)
let newX = pointer.x
let newY = pointer.y
@@ -4484,7 +4581,6 @@ export function useMode() {
canvas?.off('mouse:move')
canvas?.off('mouse:out')
- document.removeEventListener('keydown', handleKeyDown)
const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roof')
roofs.forEach((roof, index) => {
const offsetPolygonPoint = offsetPolygon(roof.points, -20)
diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js
index c2b245d7..8d16b98f 100644
--- a/src/store/canvasAtom.js
+++ b/src/store/canvasAtom.js
@@ -95,3 +95,15 @@ export const currentObjectState = atom({
default: null,
dangerouslyAllowMutability: true,
})
+
+export const horiGuideLinesState = atom({
+ key: 'horiGuideLines',
+ default: [],
+ dangerouslyAllowMutability: true,
+})
+
+export const vertGuideLinesState = atom({
+ key: 'vertGuideLines',
+ default: [],
+ dangerouslyAllowMutability: true,
+})
diff --git a/src/styles/_test.scss b/src/styles/_test.scss
index babec92c..55440362 100644
--- a/src/styles/_test.scss
+++ b/src/styles/_test.scss
@@ -1,3 +1,81 @@
.test {
background-color: #121212;
}
+
+.grid-container2 {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr); /* 2개의 열 */
+ grid-template-rows: repeat(6, 30px); /* 6개의 행 */
+ justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */
+ align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */
+ gap: 5px; /* 그리드 아이템 사이의 간격 */
+}
+
+.grid-container3 {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr); /* 3개의 열 */
+ grid-template-rows: repeat(6, 30px); /* 6개의 행 */
+ justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */
+ align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */
+ gap: 5px; /* 그리드 아이템 사이의 간격 */
+}
+
+.grid-container4 {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr); /* 4개의 열 */
+ grid-template-rows: repeat(6, 30px); /* 6개의 행 */
+ justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */
+ align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */
+ gap: 5px; /* 그리드 아이템 사이의 간격 */
+}
+
+.grid-container5 {
+ display: grid;
+ grid-template-columns: repeat(5, 1fr); /* 5개의 열 */
+ grid-template-rows: repeat(5, 30px); /* 5개의 행 */
+ justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */
+ align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */
+ gap: 0px; /* 그리드 아이템 사이의 간격 */
+}
+
+.grid-item {
+ width: 100%;
+ height: 100%;
+ border: 1px solid black; /* 그리드 외각선 */
+ text-align: center; /* 그리드 내 가운데 정렬 */
+}
+
+.grid-item2 {
+ padding: 20px;
+ text-align: center;
+ cursor: pointer;
+ border: 1px solid #000;
+}
+
+.grid-item3 {
+ padding: 20px;
+ text-align: center;
+ cursor: pointer;
+ border: 1px solid #000;
+ transition: background-color 0.3s ease;
+}
+
+.grid-item.Y {
+ background-color: #d3d0d0;
+ color: black;
+}
+
+.grid-item.N {
+ background-color: white;
+ color: black;
+}
+
+.grid-item.selected {
+ background-color: #d3d0d0;
+ color: black;
+}
+
+.grid-item.unselected {
+ background-color: white;
+ color: black;
+}
diff --git a/src/util/common-utils.js b/src/util/common-utils.js
index 9f53fede..04f3dccf 100644
--- a/src/util/common-utils.js
+++ b/src/util/common-utils.js
@@ -9,3 +9,45 @@ export const isObjectNotEmpty = (obj) => {
}
return Object.keys(obj).length > 0
}
+
+/**
+ * ex) const params = {page:10, searchDvsnCd: 20}
+ * @param {*} params
+ * @returns page=10&searchDvsnCd=20
+ */
+export const queryStringFormatter = (params = {}) => {
+ const queries = []
+ Object.keys(params).forEach((parameterKey) => {
+ const parameterValue = params[parameterKey]
+
+ if (parameterValue === undefined || parameterValue === null) {
+ return
+ }
+
+ // string trim
+ if (typeof parameterValue === 'string' && !parameterValue.trim()) {
+ return
+ }
+
+ // array to query string
+ if (Array.isArray(parameterValue)) {
+ // primitive type
+ if (parameterValue.every((v) => typeof v === 'number' || typeof v === 'string')) {
+ queries.push(`${encodeURIComponent(parameterKey)}=${parameterValue.map((v) => encodeURIComponent(v)).join(',')}`)
+ return
+ }
+ // reference type
+ if (parameterValue.every((v) => typeof v === 'object' && v !== null)) {
+ parameterValue.map((pv, i) => {
+ return Object.keys(pv).forEach((valueKey) => {
+ queries.push(`${encodeURIComponent(`${parameterKey}[${i}].${valueKey}`)}=${encodeURIComponent(pv[valueKey])}`)
+ })
+ })
+ return
+ }
+ }
+ // 나머지
+ queries.push(`${encodeURIComponent(parameterKey)}=${encodeURIComponent(parameterValue)}`)
+ })
+ return queries.join('&')
+}
diff --git a/yarn.lock b/yarn.lock
index c2324b6c..ee262584 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4319,6 +4319,11 @@ date-fns@^3.3.1:
resolved "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz"
integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==
+dayjs@^1.11.13:
+ version "1.11.13"
+ resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c"
+ integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==
+
debug@4, debug@^4.3.3, debug@^4.3.4:
version "4.3.5"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz"