diff --git a/MainLayout.codediagram b/docs/diagrams/MainLayout.codediagram
similarity index 100%
rename from MainLayout.codediagram
rename to docs/diagrams/MainLayout.codediagram
diff --git a/docs/diagrams/canvas-setting.codediagram b/docs/diagrams/canvas-setting.codediagram
new file mode 100644
index 00000000..bd87ebb4
--- /dev/null
+++ b/docs/diagrams/canvas-setting.codediagram
@@ -0,0 +1 @@
+{"id":-1,"name":"Onboarding diagram","userId":-1,"createdAt":"","updatedAt":"","content":{"items":[{"uid":"HduNR37Az-","position":{"x":800,"y":-590},"sizes":{"width":400,"height":146},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"type":"text","text":"\bCanvas Setting "},{"type":"text","marks":[{"type":"bold"}],"text":"☀️"}]},{"type":"bulletList","content":[{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"canvas 전체 내용을 설정한다."}]}]},{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"저장 버튼 없이 UI를 변경하면 Update가 일어난다."}]}]}]}]},"color":{"bgColor":"hsla(211, 33%, 22%, 1)","bgName":"blue"},"nodeType":"block"},{"uid":"DiKZ2umB3G","position":{"x":450,"y":-250},"sizes":{"width":549.78125,"height":189.5},"autoheight":true,"blockContent":{"content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/modal/setting01/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"SettingModal01.jsx"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"{buttonAct === 1 && }\n{buttonAct === 2 && }\n{buttonAct === 3 && }"}]}]},"nodeType":"block"},{"uid":"EAKK_XFrUP","position":{"x":70,"y":90},"sizes":{"width":400,"height":210},"autoheight":false,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/modal/setting01/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"FirstOption.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"디스플레이 설정"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function FirstOption(props) {"}]}]},"nodeType":"block"},{"uid":"-QZuVi6n7M","position":{"x":540,"y":90},"sizes":{"width":400,"height":182.5},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/modal/setting01/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"SecondOption.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"글꼴 및 도면 크기 설정"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function SecondOption(props) {"}]}]},"nodeType":"block"},{"uid":"OIDIoPPwFU","position":{"x":1220,"y":90},"sizes":{"width":400,"height":182.5},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/modal/setting01/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"GridOption.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"그리드 설정"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function GridOption(props) {"}]}]},"nodeType":"block"},{"uid":"iEbZe6FrdP","position":{"x":550,"y":380},"sizes":{"width":400,"height":200},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/modal/dimensionLine/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"DimensionLineSetting.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"글꼴 및 크기 변경"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function DimensionLineSetting(props) {"}]}]},"nodeType":"block"},{"uid":"5ovY6Y7atI","position":{"x":1010,"y":380},"sizes":{"width":400,"height":182.5},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/modal/grid/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"DotLineGrid.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"점, 선, 그리드 설정"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function DotLineGrid(props) {"}]}]},"nodeType":"block"},{"uid":"yVBft0fd68","position":{"x":1470,"y":380},"sizes":{"width":400,"height":200},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/common/color-picker/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"ColorPickerModal.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"색 설정"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function ColorPickerModal(props) {"}]}]},"nodeType":"block"},{"uid":"KcDc1JqWZL","position":{"x":270,"y":-700},"sizes":{"width":470,"height":336.5},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"CanvasMenu.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"modal 창 ON"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"const handlePopup = () => {\n const id = uuidv4()\n addPopup(id, 1, , true)\n}"}]},{"type":"paragraph","content":[{"type":"text","text":"canvas 설정 조회"}]},{"type":"codeBlock","attrs":{"language":"javascriptreact","wrapCode":false},"content":[{"type":"text","text":"const { fetchSettings } = useCanvasSetting()"}]}]},"nodeType":"block"},{"uid":"y2Vg-dWtlJ","position":{"x":-390,"y":-620},"sizes":{"width":520,"height":385.5},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/hooks/option/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"useCanvasSetting.js"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"canvas 설정 관리 hook"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"const fetchSettings = async () => {"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":false},"content":[{"type":"text","text":"const [settingsData, setSettingsData] = useState({\n ...settingModalFirstOptions,\n ...settingModalSecondOptions,\n ...globalFont,\n ...dotLineGridSetting,\n ...planSizeSettingMode,\n ...dimensionLineSettings,\n ...color,\n })"}]}]},"nodeType":"block"}],"configs":{"centerX":373.0590486994188,"centerY":572.9825354968084,"zoomLevel":1.017264811197917},"arrowData":{"arrowsMap":{"arrow-point-bI0wBh3Ufk-bottom-point-PSPLIYKa9J-top":{"to":"point-PSPLIYKa9J-top","from":"point-bI0wBh3Ufk-bottom","label":"Normal Box","direction":"ft","selectable":true},"arrow-point-bI0wBh3Ufk-bottom-point-ytXK_ayIc1-top":{"to":"point-ytXK_ayIc1-top","from":"point-bI0wBh3Ufk-bottom","label":"Code Box","direction":"ft","selectable":true},"arrow-point-hyyRZE3E8u-right-point-6ZopTaEaDZ-left":{"to":"point-6ZopTaEaDZ-left","from":"point-hyyRZE3E8u-right","label":"call","direction":"ft","selectable":true}},"pointsMap":{"point-PSPLIYKa9J-top":{"x":805.9999797489683,"y":60,"id":"point-PSPLIYKa9J-top","direction":"top"},"point-ytXK_ayIc1-top":{"x":205.99999493724206,"y":60,"id":"point-ytXK_ayIc1-top","direction":"top"},"point-6ZopTaEaDZ-left":{"x":220,"y":605.9999898744841,"id":"point-6ZopTaEaDZ-left","direction":"left"},"point-hyyRZE3E8u-right":{"x":100,"y":606,"id":"point-hyyRZE3E8u-right","direction":"right"},"point-bI0wBh3Ufk-bottom":{"x":515.9999797489683,"y":-40,"id":"point-bI0wBh3Ufk-bottom","direction":"bottom"}},"edgesMap":{"edge-DiKZ2umB3G-DiKZ2umB3G-bottom-EAKK_XFrUP-EAKK_XFrUP-top":{"uid":"edge-DiKZ2umB3G-DiKZ2umB3G-bottom-EAKK_XFrUP-EAKK_XFrUP-top","fromNodeId":"DiKZ2umB3G","fromHandleId":"DiKZ2umB3G-bottom","toNodeId":"EAKK_XFrUP","toHandleId":"EAKK_XFrUP-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-DiKZ2umB3G-DiKZ2umB3G-bottom--QZuVi6n7M--QZuVi6n7M-top":{"uid":"edge-DiKZ2umB3G-DiKZ2umB3G-bottom--QZuVi6n7M--QZuVi6n7M-top","fromNodeId":"DiKZ2umB3G","fromHandleId":"DiKZ2umB3G-bottom","toNodeId":"-QZuVi6n7M","toHandleId":"-QZuVi6n7M-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-DiKZ2umB3G-DiKZ2umB3G-bottom-OIDIoPPwFU-OIDIoPPwFU-top":{"uid":"edge-DiKZ2umB3G-DiKZ2umB3G-bottom-OIDIoPPwFU-OIDIoPPwFU-top","fromNodeId":"DiKZ2umB3G","fromHandleId":"DiKZ2umB3G-bottom","toNodeId":"OIDIoPPwFU","toHandleId":"OIDIoPPwFU-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge--QZuVi6n7M--QZuVi6n7M-bottom-iEbZe6FrdP-iEbZe6FrdP-top":{"uid":"edge--QZuVi6n7M--QZuVi6n7M-bottom-iEbZe6FrdP-iEbZe6FrdP-top","fromNodeId":"-QZuVi6n7M","fromHandleId":"-QZuVi6n7M-bottom","toNodeId":"iEbZe6FrdP","toHandleId":"iEbZe6FrdP-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-OIDIoPPwFU-OIDIoPPwFU-bottom-5ovY6Y7atI-5ovY6Y7atI-top":{"uid":"edge-OIDIoPPwFU-OIDIoPPwFU-bottom-5ovY6Y7atI-5ovY6Y7atI-top","fromNodeId":"OIDIoPPwFU","fromHandleId":"OIDIoPPwFU-bottom","toNodeId":"5ovY6Y7atI","toHandleId":"5ovY6Y7atI-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-OIDIoPPwFU-OIDIoPPwFU-bottom-yVBft0fd68-yVBft0fd68-top":{"uid":"edge-OIDIoPPwFU-OIDIoPPwFU-bottom-yVBft0fd68-yVBft0fd68-top","fromNodeId":"OIDIoPPwFU","fromHandleId":"OIDIoPPwFU-bottom","toNodeId":"yVBft0fd68","toHandleId":"yVBft0fd68-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-KcDc1JqWZL-KcDc1JqWZL-bottom-DiKZ2umB3G-DiKZ2umB3G-top":{"uid":"edge-KcDc1JqWZL-KcDc1JqWZL-bottom-DiKZ2umB3G-DiKZ2umB3G-top","fromNodeId":"KcDc1JqWZL","fromHandleId":"KcDc1JqWZL-bottom","toNodeId":"DiKZ2umB3G","toHandleId":"DiKZ2umB3G-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-KcDc1JqWZL-KcDc1JqWZL-left-y2Vg-dWtlJ-y2Vg-dWtlJ-right":{"uid":"edge-KcDc1JqWZL-KcDc1JqWZL-left-y2Vg-dWtlJ-y2Vg-dWtlJ-right","fromNodeId":"KcDc1JqWZL","fromHandleId":"KcDc1JqWZL-left","toNodeId":"y2Vg-dWtlJ","toHandleId":"y2Vg-dWtlJ-right","direction":"ft","selectable":true,"type":"solid","content":{"label":""}}}}}}
\ No newline at end of file
diff --git a/docs/diagrams/배치면초기설정.codediagram b/docs/diagrams/배치면초기설정.codediagram
new file mode 100644
index 00000000..814a256d
--- /dev/null
+++ b/docs/diagrams/배치면초기설정.codediagram
@@ -0,0 +1 @@
+{"id":-1,"name":"Onboarding diagram","userId":-1,"createdAt":"","updatedAt":"","content":{"items":[{"uid":"HduNR37Az-","position":{"x":690,"y":-270},"sizes":{"width":400,"height":168},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"type":"text","text":"배치면 초기설정 "},{"type":"text","marks":[{"type":"bold"}],"text":"☀️"}]},{"type":"bulletList","content":[{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"플랜당 필수 설정"}]}]},{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"필수로 설정이 저장되어야 하기 때문에 닫기 버튼 없음"}]}]},{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"저장 버튼으로 update 처리"}]}]}]}]},"color":{"bgColor":"hsla(211, 33%, 22%, 1)","bgName":"blue"},"nodeType":"block"},{"uid":"eB4rr9xOVw","position":{"x":500,"y":-40},"sizes":{"width":810,"height":182.5},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/modal/placementShape/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"PlacementShapeSetting.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"배치면 초기 설정 팝업"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, planNo, openPoint }) {"}]}]},"nodeType":"block"},{"uid":"dzN8hw1chO","position":{"x":990,"y":310},"sizes":{"width":550,"height":361},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/hooks/option/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"useCanvasSetting.js"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"/**\n * 기본설정(PlacementShapeSetting) 조회 및 초기화\n */\nconst fetchBasicSettings = async (planNo, openPoint) => {"}]},{"type":"paragraph"},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":false},"content":[{"type":"text","text":"/**\n * 기본설정(PlacementShapeSetting) 저장\n */\nconst basicSettingSave = async (params) => {"}]}]},"nodeType":"block"},{"uid":"YX7IHZIiqg","position":{"x":330,"y":310},"sizes":{"width":590,"height":259.5},"autoheight":true,"blockContent":{"content":[{"type":"filePathNode","attrs":{"pathToFile":"src/hooks/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"usePlan.js"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"/**\n * 플랜 삭제 시 배치면 초기설정 데이터 삭제\n *\n * @param {string} objectNo - 물건번호\n * @param {string} planNo - 플랜번호\n */\nconst deleteBasicSettings = async (objectNo, planNo) => {"}]}]},"nodeType":"block"}],"configs":{"centerX":47.05904869941878,"centerY":349.9825354968084,"zoomLevel":1.017264811197917},"arrowData":{"arrowsMap":{"arrow-point-bI0wBh3Ufk-bottom-point-PSPLIYKa9J-top":{"to":"point-PSPLIYKa9J-top","from":"point-bI0wBh3Ufk-bottom","label":"Normal Box","direction":"ft","selectable":true},"arrow-point-bI0wBh3Ufk-bottom-point-ytXK_ayIc1-top":{"to":"point-ytXK_ayIc1-top","from":"point-bI0wBh3Ufk-bottom","label":"Code Box","direction":"ft","selectable":true},"arrow-point-hyyRZE3E8u-right-point-6ZopTaEaDZ-left":{"to":"point-6ZopTaEaDZ-left","from":"point-hyyRZE3E8u-right","label":"call","direction":"ft","selectable":true}},"pointsMap":{"point-PSPLIYKa9J-top":{"x":805.9999797489683,"y":60,"id":"point-PSPLIYKa9J-top","direction":"top"},"point-ytXK_ayIc1-top":{"x":205.99999493724206,"y":60,"id":"point-ytXK_ayIc1-top","direction":"top"},"point-6ZopTaEaDZ-left":{"x":220,"y":605.9999898744841,"id":"point-6ZopTaEaDZ-left","direction":"left"},"point-hyyRZE3E8u-right":{"x":100,"y":606,"id":"point-hyyRZE3E8u-right","direction":"right"},"point-bI0wBh3Ufk-bottom":{"x":515.9999797489683,"y":-40,"id":"point-bI0wBh3Ufk-bottom","direction":"bottom"}},"edgesMap":{"edge-eB4rr9xOVw-eB4rr9xOVw-bottom-YX7IHZIiqg-YX7IHZIiqg-top":{"uid":"edge-eB4rr9xOVw-eB4rr9xOVw-bottom-YX7IHZIiqg-YX7IHZIiqg-top","fromNodeId":"eB4rr9xOVw","fromHandleId":"eB4rr9xOVw-bottom","toNodeId":"YX7IHZIiqg","toHandleId":"YX7IHZIiqg-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-eB4rr9xOVw-eB4rr9xOVw-bottom-dzN8hw1chO-dzN8hw1chO-top":{"uid":"edge-eB4rr9xOVw-eB4rr9xOVw-bottom-dzN8hw1chO-dzN8hw1chO-top","fromNodeId":"eB4rr9xOVw","fromHandleId":"eB4rr9xOVw-bottom","toNodeId":"dzN8hw1chO","toHandleId":"dzN8hw1chO-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}}}}}}
\ No newline at end of file
diff --git a/src/app/api/html2canvas/route.js b/src/app/api/html2canvas/route.js
deleted file mode 100644
index 21f93c82..00000000
--- a/src/app/api/html2canvas/route.js
+++ /dev/null
@@ -1,22 +0,0 @@
-'use server'
-
-import fs from 'fs/promises'
-
-import { NextResponse } from 'next/server'
-import { writeImage, writeImageBuffer } from '@/lib/fileAction'
-
-export async function GET(req) {
- const path = 'public/plan-map-images'
- const q = req.nextUrl.searchParams.get('q')
- const fileNm = req.nextUrl.searchParams.get('fileNm')
- const zoom = req.nextUrl.searchParams.get('zoom')
- const targetUrl = `https://maps.googleapis.com/maps/api/staticmap?center=${q}&zoom=${zoom}&maptype=satellite&size=640x640&scale=1&key=AIzaSyDO7nVR1N_D2tKy60hgGFavpLaXkHpiHpc`
- const decodeUrl = decodeURIComponent(targetUrl)
-
- const response = await fetch(decodeUrl)
- const data = await response.arrayBuffer()
- const buffer = Buffer.from(data)
- await writeImage(fileNm, buffer)
-
- return NextResponse.json({ fileNm: `${fileNm}.png` })
-}
diff --git a/src/app/api/image-upload/route.js b/src/app/api/image-upload/route.js
deleted file mode 100644
index 219544fe..00000000
--- a/src/app/api/image-upload/route.js
+++ /dev/null
@@ -1,15 +0,0 @@
-'use server'
-
-import { NextResponse } from 'next/server'
-import { writeImage } from '@/lib/fileAction'
-
-export async function POST(req) {
- const formData = await req.formData()
- const file = formData.get('file')
- const fileName = formData.get('fileName')
- const arrayBuffer = await file.arrayBuffer()
- const buffer = Buffer.from(arrayBuffer)
- await writeImage(fileName, buffer)
-
- return NextResponse.json({ fileNm: `${fileName}.png` })
-}
diff --git a/src/app/api/swr-tutorial/route.js b/src/app/api/swr-tutorial/route.js
deleted file mode 100644
index 99ebaf15..00000000
--- a/src/app/api/swr-tutorial/route.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import { NextResponse } from 'next/server'
-
-const defaultData = [
- {
- id: 1,
- name: 'John Doe',
- email: 'john.doe@example.com',
- },
- {
- id: 2,
- name: 'Jane Lee',
- email: 'jane.lee@example.com',
- },
-]
-
-export async function GET(req, res) {
- return NextResponse.json(defaultData)
-}
-
-export const POST = async (req, res) => {
- const { id, name, email } = await req.json()
- const newData = { id, name, email }
- console.log('🚀 ~ POST ~ newData:', newData)
- return NextResponse.json([...defaultData, newData])
-}
diff --git a/src/app/playground/page.jsx b/src/app/playground/page.jsx
deleted file mode 100644
index 3a3ad1d1..00000000
--- a/src/app/playground/page.jsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import Playground from '@/components/Playground'
-
-export default async function PlaygroundPage() {
- return (
- <>
-
- >
- )
-}
diff --git a/src/app/roof/page.jsx b/src/app/roof/page.jsx
deleted file mode 100644
index 960ffa89..00000000
--- a/src/app/roof/page.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import Hero from '@/components/Hero'
-import Roof from '@/components/Roof'
-
-export default async function RoofPage() {
- return (
- <>
-
-
-
-
- >
- )
-}
diff --git a/src/app/roof2/page.jsx b/src/app/roof2/page.jsx
deleted file mode 100644
index 94e86fbe..00000000
--- a/src/app/roof2/page.jsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import Roof2 from '@/components/Roof2'
-
-export default async function Roof2Page() {
- return (
- <>
-
-
-
- >
- )
-}
diff --git a/src/app/settings/page.jsx b/src/app/settings/page.jsx
deleted file mode 100644
index ab714682..00000000
--- a/src/app/settings/page.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import Hero from '@/components/Hero'
-import Settings from '@/components/Settings'
-
-export default async function SettingsPage() {
- return (
- <>
-
-
-
-
- >
- )
-}
diff --git a/src/components/GridSettingsModal.jsx b/src/components/GridSettingsModal.jsx
deleted file mode 100644
index 92b2e618..00000000
--- a/src/components/GridSettingsModal.jsx
+++ /dev/null
@@ -1,273 +0,0 @@
-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, horiGuideLinesState, vertGuideLinesState } from '@/store/canvasAtom'
-import { fabric } from 'fabric'
-import { ColorPicker, useColor } from 'react-color-palette'
-import 'react-color-palette/css'
-import { gridColorState } from '@/store/gridAtom'
-
-export default function GridSettingsModal(props) {
- const { canvasProps } = props
- const [isCustomGridSetting, setIsCustomGridSetting] = useState(true)
- const [gridCheckedValue, setGridCheckValue] = useState([])
- const [ratioValue, setRatioValue] = useState('1')
- const moduleLength = useRef(null) //모듈 mm 길이 입력
- const customModuleHoriLength = useRef(null)
- const customModuleVertLength = useRef(null)
-
- const [open, setOpen] = useRecoilState(modalState)
- const [guideLine, setGuideLine] = useRecoilState(guideLineState)
- const [horiGuideLines, setHoriGuideLines] = useRecoilState(horiGuideLinesState)
- const [vertGuideLines, setVertGuideLines] = useRecoilState(vertGuideLinesState)
-
- const gridSettingArray = []
-
- const gridColor = useRecoilValue(gridColorState)
- const [colorPickerShow, setColorPickerShow] = useState(false)
-
- const boxStyle = {
- width: '50px',
- height: '30px',
- border: '1px solid black',
- backgroundColor: guideColor.hex,
- }
- useEffect(() => {
- moduleLength.current.value = 90
- customModuleHoriLength.current.value = 90
- customModuleVertLength.current.value = 90
- }, [])
-
- useEffect(() => {
- setIsCustomGridSetting(ratioValue !== 'custom')
- }, [ratioValue])
-
- const drawGridSettings = () => {
- //기존에 선택된 데이터가 있으면 그 데이터를 포함한다
- if (!(Object.keys(guideLine).length === 0 && guideLine.constructor === Object)) {
- gridSettingArray.push(...guideLine)
- }
-
- let moduleHoriLength = moduleLength.current.value //가로 간격
- let moduleVertLength = moduleLength.current.value //새로 간격
-
- if (ratioValue === 'custom') {
- moduleHoriLength = customModuleHoriLength.current.value
- moduleVertLength = customModuleVertLength.current.value
- } else {
- moduleHoriLength = moduleHoriLength / ratioValue
- moduleVertLength = moduleVertLength / ratioValue
- }
-
- if (gridCheckedValue.includes('line')) {
- const horizontalLineArray = []
- const verticalLineArray = []
-
- for (let i = 0; i < canvasProps.height / moduleVertLength + 1; i++) {
- const horizontalLine = new fabric.Line(
- [0, i * moduleVertLength - moduleVertLength / 2, canvasProps.width, i * moduleVertLength - moduleVertLength / 2],
- {
- stroke: gridColor,
- strokeWidth: 1,
- selectable: true,
- lockMovementX: true,
- lockMovementY: true,
- lockRotation: true,
- lockScalingX: true,
- lockScalingY: true,
- name: 'guideLine',
- strokeDashArray: [5, 2],
- opacity: 0.3,
- direction: 'horizontal',
- },
- )
- canvasProps.add(horizontalLine)
- horizontalLineArray.push(horizontalLine)
- }
-
- for (let i = 0; i < canvasProps.width / moduleHoriLength + 1; i++) {
- const verticalLine = new fabric.Line(
- [i * moduleHoriLength - moduleHoriLength / 2, 0, i * moduleHoriLength - moduleHoriLength / 2, canvasProps.height],
- {
- stroke: gridColor,
- strokeWidth: 1,
- selectable: true,
- lockMovementX: true,
- lockMovementY: true,
- lockRotation: true,
- lockScalingX: true,
- lockScalingY: true,
- name: 'guideLine',
- strokeDashArray: [5, 2],
- opacity: 0.3,
- direction: 'vertical',
- },
- )
- canvasProps.add(verticalLine)
- verticalLineArray.push(verticalLine)
- }
- canvasProps.renderAll()
-
- const snapDistance = 10
-
- const recoilObj = {
- guideMode: 'guideLine',
- horizontalLineArray,
- verticalLineArray,
- moduleVertLength: moduleVertLength,
- 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')) {
- const circle = new fabric.Circle({
- radius: 2,
- fill: 'white',
- stroke: guideColor.hex,
- strokeWidth: 0.7,
- originX: 'center',
- originY: 'center',
- selectable: false,
- lockMovementX: true,
- lockMovementY: true,
- lockRotation: true,
- lockScalingX: true,
- lockScalingY: true,
- })
-
- const patternSourceCanvas = new fabric.StaticCanvas(null, {
- width: moduleHoriLength,
- height: moduleVertLength,
- })
-
- patternSourceCanvas.add(circle)
-
- circle.set({
- left: patternSourceCanvas.width / 2,
- top: patternSourceCanvas.height / 2,
- })
-
- patternSourceCanvas.renderAll()
-
- const pattern = new fabric.Pattern({
- source: patternSourceCanvas.getElement(),
- repeat: 'repeat',
- })
-
- const backgroundPolygon = new fabric.Polygon(
- [
- { x: 0, y: 0 },
- { x: canvasProps.width, y: 0 },
- { x: canvasProps.width, y: canvasProps.height },
- { x: 0, y: canvasProps.height },
- ],
- {
- fill: pattern,
- selectable: false,
- name: 'guideDot',
- },
- )
-
- canvasProps.add(backgroundPolygon)
- backgroundPolygon.sendToBack()
- canvasProps.renderAll()
-
- const recoilObj = {
- guideMode: 'guideDot',
- moduleVertLength: moduleVertLength,
- moduleHoriLength: moduleHoriLength,
- }
-
- gridSettingArray.push(recoilObj)
- }
- canvasProps.renderAll()
- setGuideLine(gridSettingArray)
- }
-
- const removeGuideLines = () => {
- if (!(Object.keys(guideLine).length === 0 && guideLine.constructor === Object)) {
- const guideLines = canvasProps._objects.filter((obj) => obj.name === 'guideLine' || obj.name === 'guideDot')
- guideLines?.forEach((item) => canvasProps.remove(item))
- canvasProps.renderAll()
- setGuideLine([])
- setHoriGuideLines([])
- setVertGuideLines([])
- } else {
- alert('그리드가 없습니다.')
- return
- }
- }
-
- return (
- <>
-
-
-
-
-
-
- mm
-
-
-
- 원치수
- 1/2
- 1/4
- 1/10
- 임의간격
-
-
-
- 가이드컬러
setColorPickerShow(!colorPickerShow)}>
-
- {colorPickerShow && (
-
- )}
-
-
-
- 종횡연동
-
-
-
-
-
- mm
-
-
-
- mm
-
-
-
-
-
-
-
-
- >
- )
-}
diff --git a/src/components/Headers.jsx b/src/components/Headers.jsx
deleted file mode 100644
index 02859c96..00000000
--- a/src/components/Headers.jsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import Link from 'next/link'
-
-export default function Headers() {
- return (
-
-
-
- )
-}
diff --git a/src/components/Hero.jsx b/src/components/Hero.jsx
deleted file mode 100644
index a6e7761f..00000000
--- a/src/components/Hero.jsx
+++ /dev/null
@@ -1,7 +0,0 @@
-export default function Hero(props) {
- return (
-
-
{props.title}
-
- )
-}
diff --git a/src/components/InitSettingsModal.jsx b/src/components/InitSettingsModal.jsx
deleted file mode 100644
index 4cfc483d..00000000
--- a/src/components/InitSettingsModal.jsx
+++ /dev/null
@@ -1,253 +0,0 @@
-'use client'
-
-import { useEffect, useState, memo, useCallback } from 'react'
-import { Button, Checkbox, CheckboxGroup, RadioGroup, Radio, Input, Select, SelectItem } from '@nextui-org/react'
-import { useRecoilState, useRecoilValue } from 'recoil'
-import { modalContent, modalState } from '@/store/modalAtom'
-import { canvasSettingState } from '@/store/canvasAtom'
-import { useAxios } from '@/hooks/useAxios'
-
-export default function InitSettingsModal(props) {
- const [objectNo, setObjectNo] = useState('test123240909003') // 후에 삭제 필요
- const [open, setOpen] = useRecoilState(modalState)
- const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState)
- const [roofMaterials, setRoofMaterials] = useState([])
- const [basicSetting, setBasicSettings] = useState({
- roofDrawingSet: '1',
- roofSizeSet: '1',
- roofAngleSet: 'slope',
- roofs: [{ roofSeq: '1', roofType: '3', roofWidth: '200', roofHeight: '200', roofGap: '0', roofLayout: 'parallel' }],
- })
-
- const modelProps = {
- open,
- setOpen,
- }
-
- const { get, post } = useAxios()
-
- useEffect(() => {
- get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${objectNo}` }).then((res) => {
- if (res.length == 0) return
-
- // 'roofs' 배열을 생성하여 각 항목을 추가
- const roofsRow = res.map((item) => {
- return {
- roofDrawingSet: String(item.roofDrawingSet),
- roofSizeSet: String(item.roofSizeSet),
- roofAngleSet: item.roofAngleSet,
- }
- })
-
- const roofsArray = res.some((item) => !item.roofSeq)
- ? //최초 지붕재 추가 정보의 경우 roofsArray를 초기화 설정
- [{ roofSeq: '1', roofType: '3', roofWidth: '200', roofHeight: '200', roofGap: '0', roofLayout: 'parallel' }]
- : res.map((item) => ({
- roofSeq: String(item.roofSeq),
- roofType: String(item.roofType),
- roofWidth: String(item.roofWidth),
- roofHeight: String(item.roofHeight),
- roofGap: String(item.roofGap),
- roofLayout: item.roofLayout,
- }))
-
- // 나머지 데이터와 함께 'roofs' 배열을 patternData에 넣음
- const patternData = {
- roofDrawingSet: roofsRow[0].roofDrawingSet, // 첫 번째 항목의 값을 사용
- roofSizeSet: roofsRow[0].roofSizeSet, // 첫 번째 항목의 값을 사용
- roofAngleSet: roofsRow[0].roofAngleSet, // 첫 번째 항목의 값을 사용
- roofs: roofsArray, // 만들어진 roofs 배열
- }
-
- // 데이터 설정
- setBasicSettings({ ...patternData })
- })
-
- if (!(Object.keys(canvasSetting).length === 0 && canvasSetting.constructor === Object)) {
- setBasicSettings({ ...canvasSetting })
- }
- }, [])
-
- //기본 설정값 변경 함수
- const handleBasicSetting = (event) => {
- const newBasicSetting = { ...basicSetting, [event.target.name]: event.target.value }
- setBasicSettings(newBasicSetting)
- }
-
- //배열 값 변경 함수
- const handleRoofSettings = (id, event) => {
- // 기본 세팅에서 roofs 배열을 복사
- const updatedRoofs = [...basicSetting.roofs]
-
- // roofSeq가 id와 일치하는 항목의 인덱스 찾기
- const index = updatedRoofs.findIndex((roof) => roof.roofSeq === id)
-
- if (index !== -1) {
- // 해당 인덱스의 항목을 수정
- updatedRoofs[index] = {
- ...updatedRoofs[index],
- [event.target.name]: event.target.value,
- }
-
- // 수정된 배열을 상태에 반영
- setBasicSettings((prevState) => ({
- ...prevState,
- roofs: updatedRoofs,
- }))
- }
- }
-
- //저장
- const submitCanvasConfig = async () => {
- if (!objectNo) {
- alert('object_no를 입력하세요.')
- return
- }
-
- const patternData = {
- objectNo,
- roofDrawingSet: basicSetting.roofDrawingSet,
- roofSizeSet: basicSetting.roofSizeSet,
- roofAngleSet: basicSetting.roofAngleSet,
- roofMaterialsAddList: basicSetting.roofs,
- }
- await post({ url: `/api/canvas-management/canvas-basic-settings`, data: patternData })
-
- //Recoil 설정
- setCanvasSetting({ ...basicSetting })
-
- // 저장 후 재조회
- //await handleSelect()
- }
-
- return (
- <>
-
-
배치면 초기설정
-
-
-
-
- 치수 입력에 의한 물건작성
-
-
-
-
-
-
-
- 복사도 입력
- 실측값 입력
- 육지붕
-
-
-
-
-
-
- {/* Roofs Array Rendering */}
- {basicSetting.roofs &&
- basicSetting.roofs.map((roof, index) => {
- return (
-
-
타입 :
-
-
너비 :
-
handleRoofSettings(roof.roofSeq, e)}
- />
- mm
-
높이 :
-
handleRoofSettings(roof.roofSeq, e)}
- />
- mm
-
서까래 간격 :
-
handleRoofSettings(roof.roofSeq, e)}
- />
- mm
-
- handleRoofSettings(roof.roofSeq, e)}
- >
- 병렬식
- 계단식
-
-
-
- )
- })}
-
-
-
-
- setObjectNo(e.target.value)} />
-
-
- >
- )
-}
diff --git a/src/components/Playground.jsx b/src/components/Playground.jsx
deleted file mode 100644
index 8a365646..00000000
--- a/src/components/Playground.jsx
+++ /dev/null
@@ -1,919 +0,0 @@
-'use client'
-
-import { useRef, useState, useEffect, useContext } from 'react'
-import Image from 'next/image'
-import { useRecoilState } from 'recoil'
-import { v4 as uuidv4 } from 'uuid'
-import { FaAnglesUp } from 'react-icons/fa6'
-import { FaAnglesDown } from 'react-icons/fa6'
-import { Button } from '@nextui-org/react'
-import ColorPicker from './common/color-picker/ColorPicker'
-import { cadFileNameState, googleMapFileNameState, useCadFileState, useGoogleMapFileState } from '@/store/canvasAtom'
-
-import { useAxios } from '@/hooks/useAxios'
-import { useMessage } from '@/hooks/useMessage'
-import { useMasterController } from '@/hooks/common/useMasterController'
-import { useSwal } from '@/hooks/useSwal'
-import { convertDwgToPng } from '@/lib/cadAction'
-import { GlobalDataContext } from '@/app/GlobalDataProvider'
-import QInput from './common/input/Qinput'
-import QSelect from './common/select/QSelect'
-import QPagination from './common/pagination/QPagination'
-import QSelectBox from './common/select/QSelectBox'
-import SampleReducer from './sample/SampleReducer'
-
-import styles from './playground.module.css'
-import useSWR from 'swr'
-import useSWRMutation from 'swr/mutation'
-import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
-import { canvasPopupStatusStore } from '@/store/canvasPopupStatusAtom'
-import { moduleSelectionDataPlanListState } from '@/store/selectedModuleOptions'
-import { useRouter } from 'next/navigation'
-import { QcastContext } from '@/app/QcastProvider'
-
-export default function Playground() {
- const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState)
- const [cadFileName, setCadFileName] = useRecoilState(cadFileNameState)
- const [useGoogleMapFile, setUseGoogleMapFile] = useRecoilState(useGoogleMapFileState)
- const [googleMapFileName, setGoogleMapFileName] = useRecoilState(googleMapFileNameState)
- const fileRef = useRef(null)
- const queryRef = useRef(null)
- const [zoom, setZoom] = useState(20)
- const { get, promiseGet, post, promisePost, getFetcher, postFetcher } = useAxios()
- const testVar = process.env.NEXT_PUBLIC_TEST
- const converterUrl = process.env.NEXT_PUBLIC_CONVERTER_API_URL
- const { getMessage } = useMessage()
- const { swalFire } = useSwal()
- const { getRoofMaterialList, getModuleTypeItemList, getTrestleList, getConstructionList, getTrestleDetailList } = useMasterController()
-
- const [color, setColor] = useState('#ff0000')
-
- const [textInput, setTextInput] = useState('')
- const [numberInput, setNumberInput] = useState('')
- const [radioInput, setRadioInput] = useState('')
- const [checkboxInput, setCheckboxInput] = useState([])
- const [selectedValue, setSelectedValue] = useState('')
-
- const [users, setUsers] = useState([])
-
- const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
-
- const router = useRouter()
- const { setIsGlobalLoading } = useContext(QcastContext)
-
- useEffect(() => {
- setIsGlobalLoading(false)
- }, [])
-
- useEffect(() => {
- console.log('textInput:', textInput)
- }, [textInput])
- useEffect(() => {
- console.log('numberInput:', numberInput)
- }, [numberInput])
- useEffect(() => {
- console.log('radioInput:', radioInput)
- }, [radioInput])
- useEffect(() => {
- console.log('checkboxInput:', checkboxInput)
- }, [checkboxInput])
- useEffect(() => {
- console.log('selectedValue:', selectedValue)
- }, [selectedValue])
-
- const handleUsers = async () => {
- // const users = await get('/api/user/find-all')
- const params = {
- url: '/api/user/find-all',
- }
- const users = await get(params)
- console.log('users', users)
- }
-
- const handleConvert = async () => {
- console.log('file', fileRef.current.files[0])
-
- const formData = new FormData()
- formData.append('file', fileRef.current.files[0])
-
- await promisePost({ url: converterUrl, data: formData })
- .then((res) => {
- console.log('response: ', res)
- convertDwgToPng(res.data.Files[0].FileName, res.data.Files[0].FileData)
- setUseCadFile(true)
- setCadFileName(res.data.Files[0].FileName)
- swalFire({ text: '파일 변환 완료' })
- })
- .catch((err) => {
- console.error(err)
- swalFire({ text: '파일 변환 실패' })
- })
- }
-
- const handleDownImage = async (fileName = '') => {
- const fileNm = fileName === '' ? uuidv4() : fileName
- const queryString = queryRef.current.value === '' ? '서울시 서대문구 연세로5다길 22-3 발리빌라 3층' : queryRef.current.value
- const res = await get({ url: `http://localhost:3000/api/html2canvas?q=${queryString}&fileNm=${fileNm}&zoom=${zoom}` })
- console.log('res', res)
- setGoogleMapFileName(res.fileNm)
- swalFire({ text: '이미지 저장 완료' })
- setUseGoogleMapFile(true)
- }
-
- const handleZoom = async (type) => {
- if (type === 'up') {
- setZoom((prevState) => prevState + 1)
- } else {
- setZoom((prevState) => prevState - 1)
- }
-
- await handleDownImage()
- }
-
- const data = [
- {
- id: 1,
- author: 'SWYOO',
- contents: '버튼 정리(템플릿 적용)',
- date: '2024.07.16',
- },
- {
- id: 2,
- author: 'SWYOO',
- contents: 'README.md 파일 이미지 경로 수정',
- date: '2024.07.17',
- },
- {
- id: 3,
- author: 'SWYOO',
- contents: '',
- date: '',
- },
- ]
-
- const handleSwalAlert = () => {
- swalFire({
- text: '알림 테스트입니다.',
- })
- }
-
- const paginationProps = {
- pageNo: 1,
- pageSize: 10,
- pagePerBlock: 10,
- totalCount: 26,
- handleChangePage: (page) => {
- console.log('page', page)
- },
- }
-
- useEffect(() => {
- console.log('users:', users)
- }, [users])
-
- const codes = [
- {
- clHeadCd: '203800',
- clCode: 'HEI_455',
- clCodeNm: '세로 455mm이하',
- clPriority: 1,
- name: '세로 455mm이하',
- id: 'HEI_455',
- },
- {
- clHeadCd: '203800',
- clCode: 'HEI_500',
- clCodeNm: '세로 500mm이하',
- clPriority: 2,
- name: '세로 500mm이하',
- id: 'HEI_500',
- },
- {
- clHeadCd: '203800',
- clCode: 'HEI_606',
- clCodeNm: '세로 606mm이하',
- clPriority: 3,
- name: '세로 606mm이하',
- id: 'HEI_606',
- },
- {
- clHeadCd: '203800',
- clCode: 'WID_606',
- clCodeNm: '가로 606mm이하',
- clPriority: 4,
- name: '가로 606mm이하',
- id: 'WID_606',
- },
- {
- clHeadCd: '203800',
- clCode: 'ETC',
- clCodeNm: '기타',
- clPriority: 5,
- name: '기타',
- id: 'ETC',
- },
- ]
-
- const [myData, setMyData] = useState({
- roofMatlCd: 'ROOF_ID_WA_53A',
- roofMatlNm: '화와 A',
- roofMatlNmJp: '和瓦A',
- widAuth: 'R',
- widBase: '265.000',
- lenAuth: 'R',
- lenBase: '235.000',
- roofPchAuth: null,
- roofPchBase: null,
- raftAuth: 'C',
- raftBaseCd: 'HEI_455',
- id: 'ROOF_ID_WA_53A',
- name: '화와 A',
- selected: true,
- nameJp: '和瓦A',
- length: 235,
- width: 265,
- layout: 'P',
- hajebichi: null,
- })
-
- const handleChangeMyData = () => {
- setMyData({ ...myData, raftBaseCd: 'HEI_500' })
- }
-
- const [myData2, setMyData2] = useState({})
-
- const handleChangeMyData2 = () => {
- setMyData2({
- roofMatlCd: 'ROOF_ID_WA_53A',
- roofMatlNm: '화와 A',
- roofMatlNmJp: '和瓦A',
- widAuth: 'R',
- widBase: '265.000',
- lenAuth: 'R',
- lenBase: '235.000',
- roofPchAuth: null,
- roofPchBase: null,
- raftAuth: 'C',
- raftBaseCd: 'HEI_455',
- id: 'ROOF_ID_WA_53A',
- name: '화와 A',
- selected: true,
- nameJp: '和瓦A',
- length: 235,
- width: 265,
- layout: 'P',
- hajebichi: null,
- })
- }
-
- // const [callFlag, setCallFlag] = useState(false)
- // const { data: tutoData, error, isLoading } = useSWR('http://localhost:8080/api/tutorial', getFetcher)
- // const { data: tutoData, error, isLoading } = useSWR(callFlag ? 'http://localhost:8080/api/tutorial' : null, getFetcher)
- // const { trigger, isMutating } = useSWRMutation('http://localhost:8080/api/tutorial', postFetcher)
-
- // if (isLoading) {
- // return Loading...
- // }
-
- // if (error) {
- // return Error...
- // }
-
- // const [moduleSelectionDataPlanListStore, setModuleSelectionDataPlanListStore] = useRecoilState(moduleSelectionDataPlanListState)
- // useEffect(() => {
- // console.log('🚀 ~ Playground ~ moduleSelectionDataPlanListStore:', moduleSelectionDataPlanListStore)
- // }, [moduleSelectionDataPlanListStore])
- // const { trigger: canvasPopupStatusTrigger } = useCanvasPopupStatusController({ objectNo: 'R201T01241120001', planNo: 2, popupType: 2 })
-
- return (
- <>
-
-
이 영역은 테스트입니다.
-
- {' '}
- {' '}
- {' '}
- {' '}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{testVar}
-
-
-
test']) }}>
-
-
React ColorPicker
-
-
{color}
-
-
-
캐드 파일 이미지 사용
-
-
-
-
-
-
-
구글 맵 이미지 사용
-
-
-
-
- {useGoogleMapFile && (
- <>
-
-
Zoom Controller : {zoom}
-
} className="mx-2" onClick={() => handleZoom('up')}>
-
} className="mx-2" onClick={() => handleZoom('down')}>
-
-
-
-
- >
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/*
-
{managementStateLoaded?.objectNo}
-
*/}
-
-
-
- {/*
- {tutoData &&
- tutoData.map((item) => (
-
- {item.name} / {item.email}
-
- ))}
-
-
-
-
-
-
-
*/}
-
-
-
-
-
-
-
- >
- )
-}
diff --git a/src/components/Roof.jsx b/src/components/Roof.jsx
deleted file mode 100644
index 51ba639e..00000000
--- a/src/components/Roof.jsx
+++ /dev/null
@@ -1,351 +0,0 @@
-'use client'
-
-import { useEffect } from 'react'
-import { addDistanceTextToPolygon, getDistance } from '@/util/canvas-util'
-import { useCanvas } from '@/hooks/useCanvas'
-import { fabric } from 'fabric'
-import { v4 as uuidv4 } from 'uuid'
-
-export default function Roof() {
- const {
- canvas,
- addShape,
- handleUndo,
- handleRedo,
- handleClear,
- handleCopy,
- handleDelete,
- handleSave,
- handlePaste,
- handleRotate,
- attachCustomControlOnPolygon,
- saveImage,
- handleFlip,
- } = useCanvas('canvas')
-
- useEffect(() => {
- let circle = new fabric.Circle({
- radius: 40,
- fill: 'rgba(200, 0, 0, 0.3)',
- originX: 'center',
- originY: 'center',
- })
-
- let text = new fabric.Textbox('AJLoveChina', {
- originX: 'center',
- originY: 'center',
- textAlign: 'center',
- fontSize: 12,
- })
-
- let group = new fabric.Group([circle, text], {
- left: 100,
- top: 100,
- originX: 'center',
- originY: 'center',
- })
-
- group.on('mousedblclick', () => {
- // textForEditing is temporary obj,
- // and will be removed after editing
- console.log(text.type)
- let textForEditing = new fabric.Textbox(text.text, {
- originX: 'center',
- originY: 'center',
- textAlign: text.textAlign,
- fontSize: text.fontSize,
-
- left: group.left,
- top: group.top,
- })
-
- // hide group inside text
- text.visible = false
- // note important, text cannot be hidden without this
- group.addWithUpdate()
-
- textForEditing.visible = true
- // do not give controls, do not allow move/resize/rotation on this
- textForEditing.hasConstrols = false
-
- // now add this temporary obj to canvas
- canvas.add(textForEditing)
- canvas.setActiveObject(textForEditing)
- // make the cursor showing
- textForEditing.enterEditing()
- textForEditing.selectAll()
-
- // editing:exited means you click outside of the textForEditing
- textForEditing.on('editing:exited', () => {
- let newVal = textForEditing.text
- let oldVal = text.text
-
- // then we check if text is changed
- if (newVal !== oldVal) {
- text.set({
- text: newVal,
- visible: true,
- })
-
- // comment before, you must call this
- group.addWithUpdate()
-
- // we do not need textForEditing anymore
- textForEditing.visible = false
- canvas?.remove(textForEditing)
-
- // optional, buf for better user experience
- canvas?.setActiveObject(group)
- }
- })
- })
-
- canvas?.add(group)
- }, [canvas])
-
- const addRect = () => {
- const rect = new fabric.Rect({
- height: 200,
- width: 200,
- top: 10,
- left: 10,
- opacity: 0.4,
- fill: randomColor(),
- stroke: 'red',
- name: uuidv4(),
- })
-
- addShape(rect)
- }
-
- const addHorizontalLine = () => {
- const { x1, y1, x2, y2 } = { x1: 20, y1: 100, x2: 220, y2: 100 }
- /**
- * 시작X,시작Y,도착X,도착Y 좌표
- */
- const horizontalLine = new fabric.Line([x1, y1, x2, y2], {
- name: uuidv4(),
- stroke: 'red',
- strokeWidth: 3,
- selectable: true,
- })
-
- const text = new fabric.Text(getDistance(x1, y1, x2, y2).toString(), {
- fontSize: 20,
- left: (x2 - x1) / 2,
- top: y1 - 20,
- })
-
- const group = new fabric.Group([horizontalLine, text], {
- left: 20,
- top: 20,
- })
-
- // addShape(horizontalLine)
- addShape(group)
- console.log(JSON.stringify(canvas))
- }
-
- const addVerticalLine = () => {
- const verticalLine = new fabric.Line([10, 10, 10, 100], {
- name: uuidv4(),
- stroke: 'red',
- strokeWidth: 3,
- selectable: true,
- })
-
- addShape(verticalLine)
- }
-
- const addTriangle = () => {
- const triangle = new fabric.Triangle({
- name: uuidv4(),
- top: 50,
- left: 50,
- width: 100,
- stroke: randomColor(),
- strokeWidth: 3,
- })
-
- addShape(triangle)
- }
-
- const addTrapezoid = () => {
- const trapezoid = new fabric.Polygon(
- [
- { x: 100, y: 100 }, // 좌상단
- { x: 500, y: 100 }, // 우상단
- { x: 750, y: 700 }, // 우하단
- { x: 250, y: 400 }, // 좌하단
- ],
- {
- name: uuidv4(),
- stroke: 'red',
- opacity: 0.4,
- strokeWidth: 3,
- selectable: true,
- objectCaching: false,
- },
- )
- attachCustomControlOnPolygon(trapezoid)
- const group = addDistanceTextToPolygon(trapezoid)
- addGroupClickEvent(group)
- canvas?.add(group)
- canvas?.renderAll()
- }
-
- // group에 클릭 이벤트를 추가하여 클릭 시 group을 제거하고 object들만 남기는 함수
- function addGroupClickEvent(group) {
- group.on('selected', (e) => {
- console.log(e)
- })
- group.on('mousedblclick', (e) => {
- // textForEditing is temporary obj,
- // and will be removed after editing
- const pointer = canvas?.getPointer(e.e) // 마우스 클릭 위치 가져오기
- let minDistance = Infinity
- let closestTextbox = null
- const groupPoint = group.getCenterPoint()
- group.getObjects().forEach(function (object) {
- if (object.type === 'textbox') {
- // 객체가 TextBox인지 확인
-
- const objectCenter = object.getCenterPoint() // TextBox 객체의 중심점 가져오기
- const dx = objectCenter.x + groupPoint.x - pointer.x
- const dy = objectCenter.y + groupPoint.y - pointer.y
- const distance = Math.sqrt(dx * dx + dy * dy) // 마우스 클릭 위치와 TextBox 객체 사이의 거리 계산
-
- if (distance < minDistance) {
- // 가장 짧은 거리를 가진 TextBox 객체 찾기
- minDistance = distance
- closestTextbox = object
- }
- }
- })
-
- let textForEditing = new fabric.Textbox(closestTextbox.text, {
- originX: 'center',
- originY: 'center',
- textAlign: closestTextbox.textAlign,
- fontSize: closestTextbox.fontSize,
- left: closestTextbox.left + groupPoint.x,
- top: closestTextbox.top + groupPoint.y,
- })
-
- // hide group inside text
- closestTextbox.visible = false
- // note important, text cannot be hidden without this
- group.addWithUpdate()
-
- textForEditing.visible = true
- // do not give controls, do not allow move/resize/rotation on this
- textForEditing.hasConstrols = false
-
- // now add this temporary obj to canvas
- canvas?.add(textForEditing)
- canvas?.setActiveObject(textForEditing)
- // make the cursor showing
- textForEditing?.enterEditing()
- textForEditing?.selectAll()
-
- // editing:exited means you click outside of the textForEditing
- textForEditing?.on('editing:exited', () => {
- let newVal = textForEditing.text
-
- // then we check if text is changed
- closestTextbox.set({
- text: newVal,
- visible: true,
- })
-
- // comment before, you must call this
- group.addWithUpdate()
-
- // we do not need textForEditing anymore
- textForEditing.visible = false
- canvas?.remove(textForEditing)
-
- // optional, buf for better user experience
- canvas?.setActiveObject(group)
- })
- })
- }
-
- // IText를 수정할 때 해당 값을 길이로 갖는 다른 polygon을 생성하고 다시 그룹화하는 함수
- function addTextModifiedEvent(text, polygon, index) {
- text.on('editing:exited', function () {})
- }
-
- const randomColor = () => {
- return '#' + Math.round(Math.random() * 0xffffff).toString(16)
- }
-
- return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx
deleted file mode 100644
index 731fe8c6..00000000
--- a/src/components/Roof2.jsx
+++ /dev/null
@@ -1,1099 +0,0 @@
-'use client'
-
-import { useCanvas } from '@/hooks/useCanvas'
-import { useEffect, useRef, useState } from 'react'
-import { v4 as uuidv4 } from 'uuid'
-import { useMode } from '@/hooks/useMode'
-import { LINE_TYPE, Mode } from '@/common/common'
-import { Button } from '@nextui-org/react'
-import RangeSlider from './ui/RangeSlider'
-import { useRecoilState, useRecoilValue } from 'recoil'
-import {
- cadFileCompleteState,
- cadFileNameState,
- canvasSizeState,
- compassState,
- currentObjectState,
- fontSizeState,
- globalCompassState,
- googleMapFileNameState,
- roofMaterialState,
- roofState,
- sortedPolygonArray,
- templateTypeState,
- useCadFileState,
- useGoogleMapFileState,
- wallState,
-} from '@/store/canvasAtom'
-import { QLine } from '@/components/fabric/QLine'
-import { getCanvasState, insertCanvasState } from '@/lib/canvas'
-import { calculateIntersection } from '@/util/canvas-util'
-import { QPolygon } from '@/components/fabric/QPolygon'
-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 InitSettingsModal from './InitSettingsModal'
-import GridSettingsModal from './GridSettingsModal'
-import { SurfaceShapeModal } from '@/components/ui/SurfaceShape'
-import { changeCurrentRoof, drawDirectionStringToArrow } from '@/util/qpolygon-utils'
-import ThumbnailList from '@/components/ui/ThumbnailLIst'
-import ObjectPlacement from '@/components/ui/ObjectPlacement'
-import { globalLocaleStore } from '@/store/localeAtom'
-
-export default function Roof2(props) {
- const { name, userId, email, isLoggedIn } = props
- const {
- canvas,
- handleRedo,
- handleUndo,
- setCanvasBackgroundWithDots,
- saveImage,
- addCanvas,
- handleBackImageLoadToCanvas,
- handleCadImageInit,
- backImg,
- setBackImg,
- } = useCanvas('canvas')
-
- const globalLocaleState = useRecoilValue(globalLocaleStore)
-
- const { get } = useAxios(globalLocaleState)
-
- const canvasRef = useRef(null)
-
- //canvas 기본 사이즈
- const [canvasSize, setCanvasSize] = useRecoilState(canvasSizeState)
-
- //canvas 가로 사이즈
- const [verticalSize, setVerticalSize] = useState(canvasSize.vertical)
- //canvas 세로 사이즈
- const [horizontalSize, setHorizontalSize] = useState(canvasSize.horizontal)
- // 글자크기
- const [fontSize, setFontSize] = useRecoilState(fontSizeState)
-
- const [sortedArray] = useRecoilState(sortedPolygonArray)
-
- const [angle, setAngle] = useState(0)
-
- const [showControl, setShowControl] = useState(false)
-
- //지붕재
- const roofMaterial = useRecoilValue(roofMaterialState)
-
- const [templateType, setTemplateType] = useRecoilState(templateTypeState)
-
- const [compass, setCompass] = useRecoilState(compassState)
-
- const roof = useRecoilValue(roofState)
-
- const wall = useRecoilValue(wallState)
-
- const [open, setOpen] = useRecoilState(modalState)
- const [contents, setContent] = useRecoilState(modalContent)
-
- const [scale, setScale] = useState(1)
- const currentObject = useRecoilValue(currentObjectState)
-
- //canvas 썸네일
- const [thumbnails, setThumbnails] = useState([])
- const thumbnailProps = {
- thumbnails,
- canvas,
- }
-
- let imgPath
- // cad 파일 업로드
- const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState)
- const [cadFileName, setCadFileName] = useRecoilState(cadFileNameState)
- const [cadFileComplete, setCadFileComplete] = useRecoilState(cadFileCompleteState)
- useCadFile && (imgPath = `/cadImages/${cadFileName}`)
-
- // 구글맵 이미지 업로드
- const [useGoogleMapFile, setUseGoogleMapFile] = useRecoilState(useGoogleMapFileState)
- const [googleMapFileName, setGoogleMapFileName] = useRecoilState(googleMapFileNameState)
- useGoogleMapFile && (imgPath = `/mapImages/${googleMapFileName}`)
-
- const [globalCampass, setGlobalCampass] = useRecoilState(globalCompassState)
-
- const {
- mode,
- setMode,
- changeMode,
- handleClear,
- zoomIn,
- zoomOut,
- zoom,
- togglePolygonLine,
- handleOuterlinesTest,
- handleOuterlinesTest2,
- applyTemplateB,
- makeRoofPatternPolygon,
- createRoofRack,
- drawRoofPolygon,
- drawCellInTrestle,
- drawCellManualInTrestle,
- setDirectionTrestles,
- cutHelpLines,
- } = useMode()
-
- // const [canvasState, setCanvasState] = useRecoilState(canvasAtom)
-
- useEffect(() => {
- get({ url: `/api/canvas-management/canvas-statuses/by-object/test123240822001/${userId}` }).then((res) => {
- // console.log(res)
-
- const arrangeData = res.map((item) => {
- // console.log(item.canvasStatus.replace(/##/g, '"').replace(/\\/g, ''))
- const test = item.canvasStatus.replace(/##/g, '"').replace(/\\/g, '')
- const test2 = test.substring(1, test.length - 1)
- return {
- id: item.id,
- userId: item.userId,
- imageName: `/canvasState/${item.imageName}.png`,
- canvasStatus: JSON.stringify(test2),
- }
- })
- setThumbnails(arrangeData)
- })
- }, [])
-
- useEffect(() => {
- if (!canvas) {
- return
- }
- changeMode(canvas, mode)
-
- if (!cadFileComplete && useCadFile) {
- // cad 파일 로드
- useCadFile && handleBackImageLoadToCanvas(imgPath, canvas)
- }
-
- if (useGoogleMapFile) {
- handleBackImageLoadToCanvas(imgPath, canvas)
- }
- }, [canvas, mode])
-
- const makeLine = () => {
- if (canvas) {
- const line = new QLine([50, 50, 200, 50], {
- stroke: 'black',
- selectable: true,
- strokeWidth: 2,
- fontSize: fontSize,
- })
-
- canvas?.add(line)
- }
- }
-
- const makePolygon = () => {
- if (canvas) {
- const polygon = new QPolygon(
- [
- { x: 100, y: 100 },
- { x: 600, y: 200 },
- { x: 700, y: 800 },
- { x: 100, y: 800 },
- ],
- {
- fill: 'transparent',
- stroke: 'black',
- strokeWidth: 2,
- selectable: true,
- fontSize: fontSize,
- },
- )
- canvas?.add(polygon)
-
- // polygon.fillCell({ width: 50, height: 30, padding: 10 })
- }
- }
-
- useEffect(() => {
- setCanvasSize({ ...canvasSize, vertical: parseInt(verticalSize), horizontal: parseInt(horizontalSize) })
- }, [verticalSize, horizontalSize])
-
- /**
- * 값 변경시
- */
- // useEffect(() => {
- // canvasSizeMode()
- // }, [verticalSize, horizontalSize])
- useEffect(() => {
- const { vertical, horizontal } = canvasSize
- if (vertical !== verticalSize || horizontal !== horizontalSize) {
- canvas?.setWidth(horizontalSize)
- canvas?.setHeight(verticalSize)
- canvas?.renderAll()
- }
- }, [canvasSize, canvas])
-
- const makeQPolygon = () => {
- const type1 = [
- { x: 100, y: 100 },
- { x: 850, y: 100 },
- { x: 850, y: 800 },
- { x: 500, y: 800 },
- { x: 500, y: 400 },
- { x: 100, y: 400 },
- ]
- const type2 = [
- { x: 200, y: 100 },
- { x: 200, y: 1000 },
- { x: 1100, y: 1000 },
- { x: 1100, y: 600 },
- { x: 650, y: 600 },
- { x: 650, y: 100 },
- ]
-
- const type3 = [
- { x: 200, y: 100 },
- { x: 200, y: 800 },
- { x: 500, y: 800 },
- { x: 500, y: 300 },
- { x: 800, y: 300 },
- { x: 800, y: 100 },
- ]
-
- const type4 = [
- { x: 150, y: 450 },
- { x: 150, y: 800 },
- { x: 750, y: 800 },
- { x: 750, y: 300 },
- { x: 550, y: 300 },
- { x: 550, y: 450 },
- ]
-
- const type1A = [
- { x: 67, y: 81 },
- { x: 67, y: 660 },
- { x: 437, y: 660 },
- { x: 437, y: 1190 },
- { x: 858, y: 1190 },
- { x: 858, y: 81 },
- ]
-
- const type1B = [
- { x: 137, y: 42 },
- { x: 137, y: 621 },
- { x: 667, y: 621 },
- { x: 667, y: 991 },
- { x: 1088, y: 991 },
- { x: 1088, y: 42 },
- ]
-
- const eightPoint = [
- { x: 240.1111, y: 130.1111 },
- { x: 240.1111, y: 630.1111 },
- { x: 640.1111, y: 630.1111 },
- { x: 640.1111, y: 480.1111 },
- { x: 440.1111, y: 480.1111 },
- { x: 440.1111, y: 280.1111 },
- { x: 740.1111, y: 280.1111 },
- { x: 740.1111, y: 130.1111 },
- ]
-
- const eightPoint2 = [
- { x: 197, y: 215 },
- { x: 197, y: 815 },
- { x: 397, y: 815 },
- { x: 397, y: 1115 },
- { x: 697, y: 1115 },
- { x: 697, y: 815 },
- { x: 897, y: 815 },
- { x: 897, y: 215 },
- ]
-
- const eightPoint3 = [
- { x: 190, y: 147 },
- { x: 190, y: 747 },
- { x: 490, y: 747 },
- { x: 490, y: 497 },
- { x: 640, y: 497 },
- { x: 640, y: 747 },
- { x: 1090, y: 747 },
- { x: 1090, y: 147 },
- ]
-
- const eightPoint4 = [
- { x: 200, y: 200 },
- { x: 200, y: 400 },
- { x: 500, y: 400 },
- { x: 500, y: 700 },
- { x: 800, y: 700 },
- { x: 800, y: 400 },
- { x: 1100, y: 400 },
- { x: 1100, y: 200 },
- ]
-
- const eightPoint5 = [
- { x: 140, y: 101 },
- { x: 140, y: 601 },
- { x: 440, y: 601 },
- { x: 440, y: 801 },
- { x: 840, y: 801 },
- { x: 840, y: 601 },
- { x: 1140, y: 601 },
- { x: 1140, y: 101 },
- ]
-
- const twelvePoint = [
- { x: 195, y: 166 },
- { x: 195, y: 466 },
- { x: 395, y: 466 },
- { x: 395, y: 766 },
- { x: 545, y: 766 },
- { x: 545, y: 466 },
- { x: 695, y: 466 },
- { x: 695, y: 666 },
- { x: 845, y: 666 },
- { x: 845, y: 466 },
- { x: 995, y: 466 },
- { x: 995, y: 166 },
- ]
-
- const twelvePoint2 = [
- { x: 165, y: 81 },
- { x: 165, y: 1081 },
- { x: 465, y: 1081 },
- { x: 465, y: 781 },
- { x: 765, y: 781 },
- { x: 765, y: 1081 },
- { x: 1065, y: 1081 },
- { x: 1065, y: 581 },
- { x: 765, y: 581 },
- { x: 765, y: 281 },
- { x: 1065, y: 281 },
- { x: 1065, y: 81 },
- ]
-
- const complicatedType = [
- { x: 100, y: 100 },
- { x: 100, y: 1100 },
- { x: 400, y: 1100 },
- { x: 400, y: 800 },
- { x: 700, y: 800 },
- { x: 700, y: 1100 },
- { x: 1000, y: 1100 },
- { x: 1000, y: 600 },
- { x: 700, y: 600 },
- { x: 700, y: 300 },
- { x: 1000, y: 300 },
- { x: 1000, y: 100 },
- ]
-
- const testType = [
- { x: 500, y: 400 },
- { x: 650, y: 550 },
- { x: 575, y: 625 },
- { x: 325, y: 625 },
- { x: 100, y: 400 },
- ]
-
- const testType2 = [
- { x: 100, y: 400 },
- { x: 325, y: 625 },
- { x: 575, y: 625 },
- { x: 650, y: 550 },
- { x: 500, y: 400 },
- ]
-
- const triangleType = [
- { x: 100, y: 100 },
- { x: 100, y: 600 },
- { x: 600, y: 600 },
- { x: 600, y: 100 },
- ]
-
- const rectangleType1 = [
- { x: 500, y: 100 },
- { x: 500, y: 800 },
- { x: 900, y: 800 },
- { x: 900, y: 100 },
- ]
-
- const rectangleType2 = [
- { x: 100, y: 100 },
- { x: 100, y: 300 },
- { x: 600, y: 300 },
- { x: 600, y: 100 },
- ]
-
- const types = [type1, type2, type3, type4, type1A, type1B, eightPoint, eightPoint2, eightPoint3, eightPoint4, twelvePoint]
- const newP = [
- { x: 450, y: 450 },
- { x: 650, y: 250 },
- { x: 675, y: 275 },
- { x: 450, y: 850 },
- ]
-
- const test1 = [
- { x: 381, y: 178 },
- { x: 381, y: 659.3 },
- { x: 773.3, y: 659.3 },
- { x: 773.3, y: 497.9 },
- { x: 1457, y: 497.9 },
- { x: 1457, y: 178 },
- ]
-
- const test2 = [
- { x: 113, y: 114.9 },
- { x: 113, y: 371.9 },
- { x: 762, y: 371.9 },
- { x: 762, y: 818.7 },
- { x: 1478.6, y: 818.7 },
- { x: 1478.6, y: 114.9 },
- ]
-
- const test3 = [
- { x: 100, y: 100 },
- { x: 100, y: 600 },
- { x: 600, y: 600 },
- { x: 600, y: 100 },
- { x: 500, y: 100 },
- { x: 500, y: 200 },
- { x: 200, y: 200 },
- { x: 200, y: 100 },
- ]
-
- const test4 = [
- { x: 100, y: 100 },
- { x: 100, y: 1000 },
- { x: 1100, y: 1000 },
- { x: 1100, y: 550 },
- { x: 500, y: 550 },
- { x: 500, y: 100 },
- ]
-
- const polygon = new QPolygon(test4, {
- fill: 'transparent',
- stroke: 'green',
- strokeWidth: 1,
- selectable: false,
- fontSize: fontSize,
- name: 'wall',
- })
-
- canvas?.add(polygon)
- handleOuterlinesTest2(polygon, 50)
- setTemplateType(1)
- }
-
- const rotateShape = () => {
- if (canvas) {
- const activeObject = canvas?.getActiveObject()
-
- if (activeObject) {
- activeObject.rotate(angle)
- canvas?.renderAll()
- }
- }
- }
-
- const makeQLine = () => {
- if (canvas) {
- const line = new QLine([50, 250, 900, 250], {
- stroke: 'black',
- strokeWidth: 5,
- fontSize: fontSize,
- selectable: true,
- })
-
- const line2 = new QLine([450, 450, 821, 78], {
- stroke: 'black',
- strokeWidth: 5,
- fontSize: fontSize,
- selectable: true,
- })
-
- canvas?.add(line)
- canvas?.add(line2)
-
- const interSectionPoint = calculateIntersection(line, line2)
-
- if (interSectionPoint) {
- const circle = new fabric.Circle({
- radius: 5,
- fill: 'red',
- left: interSectionPoint.x - 5,
- top: interSectionPoint.y - 5,
- })
-
- canvas?.add(circle)
- }
- }
- }
-
- const addBackgroundInPolygon = (polygon) => {
- fabric.Image.fromURL('assets/img/check2.png', function (img) {
- // 패턴 객체를 생성합니다.
- const pattern = new fabric.Pattern({
- source: img.getElement(),
- repeat: 'repeat',
- })
-
- polygon.fillBackground(pattern)
- })
- }
-
- function PolygonToLine() {
- const polygon = canvas?.getActiveObject()
-
- if (polygon.type !== 'QPolygon') {
- return
- }
-
- const lines = togglePolygonLine(polygon)
- }
-
- /**
- * canvas 내용 저장하기
- */
- const handleSaveCanvas = async () => {
- // const jsonStr = JSON.stringify(canvas?.toDatalessJSON(['type', 'fontSize']))
- const jsonObj = JSON.stringify(canvas?.toDatalessJSON(['type', 'fontSize', 'lines']))
- console.log(jsonObj)
-
- const param = {
- loginId: 'test',
- canvas: jsonObj,
- }
- console.log(param)
-
- await insertCanvasState(param)
- handleClear()
- }
-
- const drawRoofMaterial = () => {
- const { width, height, roofStyle } = roofMaterial
-
- const wallPolygon = canvas?.getObjects().find((obj) => obj.name === 'wall')
-
- wallPolygon.set('strokeDashArray', [10, 5, 2, 5])
- wallPolygon.set('stroke', 'blue')
- wallPolygon.set('strokeWidth', 1)
-
- const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roof')
-
- roofs.forEach((roof) => {
- let maxLengthLine = roof.lines.reduce((acc, cur) => {
- return acc.length > cur.length ? acc : cur
- })
-
- const roofRatio = window.devicePixelRatio || 1
-
- // 패턴 소스를 위한 임시 캔버스 생성
- const patternSourceCanvas = document.createElement('canvas')
- if (roofStyle === 1) {
- if (maxLengthLine.direction === 'right' || maxLengthLine.direction === 'left') {
- patternSourceCanvas.width = width * roofRatio
- patternSourceCanvas.height = height * roofRatio
- } else {
- patternSourceCanvas.width = height * roofRatio
- patternSourceCanvas.height = width * roofRatio
- }
- } else if (roofStyle === 2) {
- if (maxLengthLine.direction === 'right' || maxLengthLine.direction === 'left') {
- patternSourceCanvas.width = width * 2
- patternSourceCanvas.height = height * 2
- } else {
- patternSourceCanvas.width = height * 2
- patternSourceCanvas.height = width * 2
- }
- }
-
- const ctx = patternSourceCanvas.getContext('2d')
-
- ctx.scale(roofRatio, roofRatio)
- ctx.strokeStyle = 'green'
- ctx.lineWidth = 0.4
- // 벽돌 패턴 그리기
- if (roofStyle === 1) {
- ctx.strokeRect(0, 0, 50, 30)
- } else if (roofStyle === 2) {
- // 지그재그
- ctx.strokeRect(0, 0, 200, 100)
- ctx.strokeRect(100, 100, 200, 100)
- }
-
- // 패턴 생성
- const pattern = new fabric.Pattern({
- source: patternSourceCanvas,
- repeat: 'repeat',
- })
- roof.set('fill', null)
-
- roof.set('fill', pattern)
- canvas?.renderAll()
- })
- }
-
- /**
- * canvas 내용 불러오기
- */
- const handleLoadCanvas = async () => {
- const canvasStates = await getCanvasState()
- console.log(JSON.parse(canvasStates.canvas))
- canvas?.loadFromJSON(JSON.parse(canvasStates.canvas))
- }
-
- /**
- * 컨트롤러 보이기/숨기기
- */
- const handleShowController = () => {
- setShowControl(!showControl)
- }
-
- const drawRoofPatterns = (roofStyle) => {
- makeRoofPatternPolygon(roofStyle)
- }
-
- const deleteCell = () => {
- const selectedCells = canvas?.getObjects().filter((obj) => obj.name === 'cell' && obj.selected)
-
- selectedCells.forEach((cell) => {
- canvas?.remove(cell)
- })
- }
-
- const setCompassState = (degree) => {
- setCompass(degree)
- }
-
- const changeLength = (e) => {
- const polygon = canvas?.getActiveObject()
-
- if (polygon?.type !== 'QPolygon') {
- return
- }
- setScale(e)
- polygon.setScaleX(e)
-
- canvas?.renderAll()
- }
-
- const moduleConfiguration = () => {
- createRoofRack()
- }
-
- const setDirectionStringToArrow = () => {
- drawDirectionStringToArrow(canvas, globalCampass)
-
- /**
- * 나중에 유틸로 다시 구현
- */
- // const groupShapes = canvas?.getObjects().filter((obj) => obj.name === 'cellGroup')
-
- // console.log('groupShapes', groupShapes)
-
- // groupShapes.forEach((obj) => {
- // let originAngle = obj._objects.find((array) => array.originAngle !== undefined).originAngle
-
- // console.log('originAngle', originAngle)
-
- // let rotateAngle = globalCampass
-
- // // let rotateAngle = originAngle + globalCampass
- // // if (rotateAngle > 360) {
- // // rotateAngle -= 360
- // // }
-
- // console.log('rotateAngle', rotateAngle)
-
- // obj.set({ angle: rotateAngle, originX: 'center', originY: 'center' })
- // obj.setCoords()
- // })
- canvas?.renderAll()
- }
-
- const setHipRoof = () => {
- const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof')
- const currentRoof = polygon.lines[2]
- currentRoof.attributes.type = LINE_TYPE.WALLLINE.EAVES
- currentRoof.attributes.offset = 50
- changeCurrentRoof(currentRoof, canvas)
- }
- const setGableRoof = () => {
- const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof')
- const currentRoof = polygon.lines[2]
- currentRoof.attributes.type = LINE_TYPE.WALLLINE.GABLE
- currentRoof.attributes.offset = 30
- changeCurrentRoof(currentRoof, canvas)
- }
- const setHipAndGableRoof = () => {
- let offset = Number(prompt('팔작지붕 폭', '50'))
- if (!isNaN(offset) && offset > 0) {
- const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof')
- const currentRoof = polygon.lines[2]
- currentRoof.attributes.type = LINE_TYPE.WALLLINE.HIPANDGABLE
- currentRoof.attributes.width = offset
- changeCurrentRoof(currentRoof, canvas)
- } else {
- alert('폭은 0 보다 커야 함')
- }
- }
- const setJerkInHeadRoof = () => {
- let offset = Number(prompt('팔작지붕 폭', '50'))
- if (!isNaN(offset) && offset > 0) {
- const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof')
- const currentRoof = polygon.lines[2]
- currentRoof.attributes.type = LINE_TYPE.WALLLINE.JERKINHEAD
- currentRoof.attributes.width = offset
- changeCurrentRoof(currentRoof, canvas)
- } else {
- alert('폭은 0 보다 커야 함')
- }
- }
- const setWallRoof = () => {
- let offset = Number(prompt('소매 폭', '0'))
- const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof')
- const currentRoof = polygon.lines[2]
- currentRoof.attributes.type = LINE_TYPE.WALLLINE.WALL
- currentRoof.attributes.width = offset
- changeCurrentRoof(currentRoof, canvas)
- }
- return (
- <>
- {canvas && (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {
-
- }
-
- 현재 줌 : {zoom}%
-
-
- {/*{templateType === 0 && (*/}
- {/* <>*/}
-
- {/* >*/}
- {/*)}*/}
-
-
-
-
-
-
-
-
- {/**/}
- {/*
-
- */}
-
- {templateType === 1 && (
- <>
-
-
-
-
- >
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- )}
-
- {/*
-
각도 입력(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
-
-
*/}
-
-
- {!canvas ? null : mode === Mode.DRAW_LINE ? (
-
- ) : currentObject?.type === 'QPolygon' ? (
-
- ) : currentObject?.type === 'QLine' ? (
-
- ) : (
-
- )}
-
- >
- )
-}
diff --git a/src/components/Settings.jsx b/src/components/Settings.jsx
deleted file mode 100644
index 51680711..00000000
--- a/src/components/Settings.jsx
+++ /dev/null
@@ -1,324 +0,0 @@
-'use client'
-
-import React, { useEffect, useState } from 'react'
-import { Button } from '@nextui-org/react'
-
-import { useAxios } from '@/hooks/useAxios'
-
-import { useRecoilState } from 'recoil'
-import { customSettingsState } from '@/store/canvasAtom'
-import { modalContent, modalState } from '@/store/modalAtom'
-
-import ColorPicker from './common/color-picker/ColorPicker'
-
-export default function Settings() {
- const [objectNo, setObjectNo] = useState('test123240829010')
- const [error, setError] = useState(null)
- const [customSettings, setCustomSettings] = useRecoilState(customSettingsState)
-
- const [color, setColor] = useState('#ff0000')
-
- const [open, setOpen] = useRecoilState(modalState)
- const [contents, setContent] = useRecoilState(modalContent)
-
- const { get, post } = useAxios()
-
- const handleSavePopup = () => {
- console.log('color ', color)
- }
-
- const handleClosePopup = () => {
- setContent('')
- setOpen(false)
- console.log('colorSetting ', color)
- }
-
- const colorSetting = (
- <>
-
- React ColorPicker
-
- {color}
-
- >
- )
-
- const customStyles = {
- overlay: {
- backgroundColor: 'rgba(0,0,0,0.5)',
- },
- content: {
- width: '300px',
- height: '400px',
- margin: 'auto',
- borderRadius: '4px',
- boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
- padding: '20px',
- },
- }
-
- // 상태를 하나의 객체로 관리
- const [settings, setSettings] = useState({
- display1: Array(11).fill(false), // 화면 표시1
- display2: Array(3).fill(false), // 화면 표시2
- rangeSetting: 0, // 흡착 범위 설정
- gridSettings: Array(5).fill(false), // 그리드 설정
- })
-
- const gridItems = {
- display1: [
- '할당 표시',
- '도면 표시',
- '그리드 표시',
- '문자 표시',
- '흐름방향 표시',
- '복도치수 표시',
- '실제치수 표시',
- '치수 표시 없음',
- '가대 표시',
- '좌표 표시',
- '도면전환 표시',
- ],
- display2: ['테두리만', '라인해치', 'All Painted'],
- rangeSetting: ['극소', '소', '중', '대'],
- gridSettings: ['임의 그리드', '실선 그리드', '점 그리드', '그리드 색 설정', '흡착점 추가'],
- }
-
- // 초기 조회
- useEffect(() => {
- if (!objectNo) {
- alert('object_no를 입력하세요.')
- }
- }, [])
-
- // 클릭 시 상태 변경 함수
- const handleToggle = (type, index) => {
- // '실선 그리드' 클릭 시 팝업 열기
- if (type === 'gridSettings' && gridItems.gridSettings[index] === '실선 그리드') {
- //openGridPopup()
- }
-
- // '그리드 색 설정' 클릭 시 팝업 열기
- if (type === 'gridSettings' && gridItems.gridSettings[index] === '그리드 색 설정') {
- //setSelectedGridSetting(gridItems.gridSettings[index])
- //setIsPopupOpen(true)
- //return prevSettings // 설정은 변경하지 않음
-
- setOpen(true)
- setContent({ ...colorSetting })
- }
-
- setSettings((prevSettings) => {
- // prevSettings[type]이 배열인지 확인하고, 그렇지 않은 경우 빈 배열로 초기화
- let updated = Array.isArray(prevSettings[type]) ? [...prevSettings[type]] : []
-
- if (type === 'rangeSetting') {
- return { ...prevSettings, [type]: index }
- }
-
- updated[index] = updated[index] === false ? true : false
- return { ...prevSettings, [type]: updated }
- })
- }
-
- // '실선 그리드' 클릭 시 팝업을 열기 위한 함수
- const openGridPopup = () => {
- const popupWidth = 500
- const popupHeight = 300
-
- // 팝업 창 위치를 화면 중앙으로 조정하기 위해 계산
- const left = window.innerWidth / 2 - popupWidth / 2
- const top = window.innerHeight / 2 - popupHeight / 2
-
- // 새 창 열기
- window
- .open
- //'./components/intro', // 팝업으로 띄울 페이지의 URL
- //'_blank', // 새 창으로 열기
- //`width=${popupWidth},height=${popupHeight},top=${top},left=${left}`, // 크기와 위치 지정
- ()
- }
-
- // Canvas Setting 조회 및 초기화
- const handleSelect = async () => {
- try {
- if (!objectNo) {
- alert('object_no를 입력하세요.')
- return
- }
-
- const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` })
-
- // 데이터가 없는 경우
- if (!res) {
- console.warn('조회 결과가 없습니다.')
- // 기본값을 설정하거나 사용자에게 알림 표시
- setSettings({
- display1: Array(11).fill(false), // 화면 표시1 기본값
- display2: Array(3).fill(false), // 화면 표시2 기본값
- rangeSetting: 0, // 흡착 범위 설정 기본값
- gridSettings: Array(5).fill(false), // 그리드 설정 기본값
- })
-
- alert('조회된 데이터가 없습니다. 기본 설정이 적용됩니다.')
- return // 이후 코드 실행을 중단
- }
-
- const data = {
- display1: [
- res.assignDisplay,
- res.drawDisplay,
- res.gridDisplay,
- res.charDisplay,
- res.flowDisplay,
- res.hallwayDimenDisplay,
- res.actualDimenDisplay,
- res.noDimenDisplay,
- res.trestleDisplay,
- res.coordiDisplay,
- res.drawConverDisplay,
- ],
- display2: [res.onlyBorder, res.lineHatch, res.allPainted],
- rangeSetting: res.adsorpRangeSetting,
- gridSettings: [res.randomGrid, res.solidGrid, res.dotGrid, res.gridColorSet, res.adsorpPointAdd],
- }
-
- // 데이터 설정
- setSettings({
- display1: data.display1,
- display2: data.display2,
- rangeSetting: data.rangeSetting,
- gridSettings: data.gridSettings,
- })
- } catch (error) {
- console.error('Data fetching error:', error)
- }
- }
-
- // Canvas Setting 저장
- const handleSubmit = async () => {
- 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: settings.rangeSetting,
- randomGrid: settings.gridSettings[0],
- solidGrid: settings.gridSettings[1],
- dotGrid: settings.gridSettings[2],
- gridColorSet: settings.gridSettings[3],
- adsorpPointAdd: settings.gridSettings[4],
- }
-
- console.log('patternData', patternData)
-
- await post({ url: `/api/canvas-management/canvas-settings`, data: patternData })
-
- //Recoil 설정
- setCustomSettings({ ...patternData })
-
- // 저장 후 재조회
- await handleSelect()
- }
-
- 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)}
- >
- {item}
-
- ))}
-
-
-
치수선 설정
-
도면 크기 설정
-
흡착점 ON
-
-
[그리드 설정]
-
-
- {gridItems.gridSettings.map((item, index) => (
-
handleToggle('gridSettings', index)}
- >
- {settings.gridSettings[index]} {item}
-
- ))}
-
-
-
- >
- )
-}
diff --git a/src/components/estimate/Estimate.jsx b/src/components/estimate/Estimate.jsx
index deb95caf..72e7bb30 100644
--- a/src/components/estimate/Estimate.jsx
+++ b/src/components/estimate/Estimate.jsx
@@ -87,7 +87,7 @@ export default function Estimate({}) {
const { getMessage } = useMessage()
const { closeAll } = usePopup()
- const { setMenuNumber } = useCanvasMenu()
+ const { setSelectedMenu } = useCanvasMenu()
//새로 추가한 첨부파일 props
const fileUploadProps = {
uploadFiles: files,
@@ -142,7 +142,7 @@ export default function Estimate({}) {
}, [selectedPlan])
useEffect(() => {
- setMenuNumber(5)
+ setSelectedMenu('estimate')
initEstimate()
}, [])
diff --git a/src/components/estimate/EstimateFileUploader.jsx b/src/components/estimate/EstimateFileUploader.jsx
index 950ed6af..c02d4637 100644
--- a/src/components/estimate/EstimateFileUploader.jsx
+++ b/src/components/estimate/EstimateFileUploader.jsx
@@ -3,11 +3,14 @@
import { useRef } from 'react'
import { v4 as uuidv4 } from 'uuid'
import { useMessage } from '@/hooks/useMessage'
+import { useSwal } from '@/hooks/useSwal'
export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) {
const fileInputRef = useRef(null)
const { getMessage } = useMessage()
+ const { swalFire } = useSwal()
+
const handleButtonClick = (e) => {
e.preventDefault()
fileInputRef.current.click()
@@ -20,9 +23,16 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) {
const fileList = []
let passFlag = true
+ const allowedFileTypes = [
+ 'image/',
+ 'application/pdf',
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'application/vnd.ms-excel',
+ ]
Array.from(e.target.files).forEach((file) => {
- let fileType = file.type
- if (!fileType.includes('image')) {
+ //엑셀, pdf, 이미지
+ const fileType = file.type
+ if (!allowedFileTypes.some((type) => fileType.includes(type))) {
passFlag = false
} else {
fileList.push({ data: file, id: uuidv4() })
@@ -30,30 +40,11 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) {
})
if (!passFlag) {
- alert(getMessage('estimate.detail.fileList.extCheck'))
+ swalFire({ text: getMessage('estimate.detail.fileList.extCheck'), type: 'alert', icon: 'error' })
}
- // const { files } = e.target
- // const file = files[0]
- // const fileType = file.type
- // if (!fileType.includes('image')) {
- // return alert(getMessage('estimate.detail.fileList.extCheck'))
- // }
-
- // setUploadFiles([...uploadFiles, { data: e.target.files[0], id: uuidv4() }])
- //다중으로 변경
setUploadFiles([...uploadFiles, ...fileList])
e.target.value = ''
- // const formData = new FormData()
- // formData.append('file', e.target.files[0])
- // formData.append('objectNo', objectNo) // 받아와야 하는 값
- // formData.append('planNo', planNo) // 받아와야 하는 값
- // formData.append('category', category) // 받아와야 하는 값
- // formData.append('userId', session.userId)
-
- // await promisePost({ url: '/api/file/fileUpload', data: formData }).then((res) => {
- // if (res.data > 0) setUploadFiles([...files, { name: e.target.files[0].name, id: uuidv4() }])
- // })
}
const deleteFile = (id) => {
@@ -65,10 +56,17 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) {
e.stopPropagation()
const fileList = []
let passFlag = true
+ const allowedFileTypes = [
+ 'image/',
+ 'application/pdf',
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'application/vnd.ms-excel',
+ ]
Array.from(e.dataTransfer.files).forEach((file) => {
+ //엑셀, pdf, 이미지
let fileType = file.type
- if (!fileType.includes('image')) {
+ if (!allowedFileTypes.some((type) => fileType.includes(type))) {
passFlag = false
} else {
fileList.push({ data: file, id: uuidv4() })
@@ -76,7 +74,7 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) {
})
if (!passFlag) {
- alert(getMessage('estimate.detail.fileList.extCheck'))
+ swalFire({ text: getMessage('estimate.detail.fileList.extCheck'), type: 'alert', icon: 'error' })
}
setUploadFiles([...uploadFiles, ...fileList])
@@ -103,16 +101,7 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) {
- onChangeFiles(e)}
- />
+ onChangeFiles(e)} />
-
+
{plans.map((plan, index) => (