From dcdbb626f79b08ff808d057d9d28e4e88149c774 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Fri, 6 Sep 2024 10:19:31 +0900 Subject: [PATCH 1/4] Refactor file upload and image handling in Playground and Roof2 components --- src/app/api/html2canvas/route.js | 28 ++++++++++++++++++++++++++++ src/components/Playground.jsx | 32 ++++++++++++++++++++++++++------ src/components/Roof2.jsx | 20 ++++++++++++++++---- src/hooks/useCanvas.js | 4 ++-- src/store/canvasAtom.js | 11 +++++++++++ 5 files changed, 83 insertions(+), 12 deletions(-) create mode 100644 src/app/api/html2canvas/route.js diff --git a/src/app/api/html2canvas/route.js b/src/app/api/html2canvas/route.js new file mode 100644 index 00000000..c1e6284d --- /dev/null +++ b/src/app/api/html2canvas/route.js @@ -0,0 +1,28 @@ +'use server' + +import fs from 'fs/promises' + +import { NextResponse } from 'next/server' + +export async function GET(req) { + const path = 'public/mapImages' + const q = req.nextUrl.searchParams.get('q') + const fileNm = req.nextUrl.searchParams.get('fileNm') + const targetUrl = `https://maps.googleapis.com/maps/api/staticmap?center=${q}&zoom=21&maptype=satellite&size=750x750&scale=2&key=AIzaSyDO7nVR1N_D2tKy60hgGFavpLaXkHpiHpc` + const decodeUrl = decodeURIComponent(targetUrl) + + const response = await fetch(decodeUrl) + + const data = await response.arrayBuffer() + const buffer = Buffer.from(data) + + try { + await fs.readdir(path) + } catch { + await fs.mkdir(path) + } finally { + await fs.writeFile(`${path}/${fileNm}.png`, buffer) + } + + return NextResponse.json({ fileNm: `${fileNm}.png` }) +} diff --git a/src/components/Playground.jsx b/src/components/Playground.jsx index 624113de..46560aca 100644 --- a/src/components/Playground.jsx +++ b/src/components/Playground.jsx @@ -1,25 +1,28 @@ 'use client' import { useRef, useState } from 'react' -import { Button } from '@nextui-org/react' -import ColorPicker from './common/color-picker/ColorPicker' +import { useRecoilState } from 'recoil' +import { v4 as uuidv4 } from 'uuid' import { useAxios } from '@/hooks/useAxios' import { useMessage } from '@/hooks/useMessage' import { convertDwgToPng } from '@/lib/cadAction' -// import { get } from '@/lib/Axios' +import { cadFileNameState, googleMapFileNameState, useCadFileState, useGoogleMapFileState } from '@/store/canvasAtom' import QSelect from '@/components/ui/QSelect' +import { Button } from '@nextui-org/react' +import ColorPicker from './common/color-picker/ColorPicker' +import { toastUp } from '@/hooks/useToast' import styles from './playground.module.css' -import { useRecoilState } from 'recoil' -import { cadFileNameState, useCadFileState } from '@/store/canvasAtom' -import { toastUp } from '@/hooks/useToast' 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 { get, promisePost } = useAxios() const testVar = process.env.NEXT_PUBLIC_TEST const converterUrl = process.env.NEXT_PUBLIC_CONVERTER_API_URL @@ -56,6 +59,15 @@ export default function Playground() { }) } + const handleDownImage = async () => { + setUseGoogleMapFile(true) + 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=${uuidv4()}` }) + console.log('res', res) + setGoogleMapFileName(res.fileNm) + toastUp({ message: '이미지 저장 완료', type: 'success' }) + } + const data = [ { id: 1, @@ -99,11 +111,19 @@ export default function Playground() {
{color}
+

캐드 파일 이미지 사용

+
+

구글 맵 이미지 사용

+ +
+ +
+
) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index ecbc083b..670f58c4 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -16,11 +16,13 @@ import { currentObjectState, fontSizeState, globalCompassState, + googleMapFileNameState, roofMaterialState, roofState, sortedPolygonArray, templateTypeState, useCadFileState, + useGoogleMapFileState, wallState, } from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' @@ -49,7 +51,7 @@ export default function Roof2(props) { setCanvasBackgroundWithDots, saveImage, addCanvas, - handleCadImageLoad, + handleBackImageLoadToCanvas, handleCadImageInit, backImg, setBackImg, @@ -99,13 +101,18 @@ export default function Roof2(props) { canvas, } + let imgPath // cad 파일 업로드 const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState) const [cadFileName, setCadFileName] = useRecoilState(cadFileNameState) const [cadFileComplete, setCadFileComplete] = useRecoilState(cadFileCompleteState) - let imgPath useCadFile && (imgPath = `/cadImages/${cadFileName}`) + // 구글맵 이미지 업로드 + const [useGoogleMapFile, setUseGoogleMapFile] = useRecoilState(useGoogleMapFileState) + const [googleMapFileName, setGoogleMapFileName] = useRecoilState(googleMapFileNameState) + useGoogleMapFile && (imgPath = `/mapImages/${googleMapFileName}`) + const [globalCampass, setGlobalCampass] = useRecoilState(globalCompassState) const { @@ -157,7 +164,11 @@ export default function Roof2(props) { if (!cadFileComplete && useCadFile) { // cad 파일 로드 - useCadFile && handleCadImageLoad(imgPath, canvas) + useCadFile && handleBackImageLoadToCanvas(imgPath, canvas) + } + + if (useGoogleMapFile) { + handleBackImageLoadToCanvas(imgPath, canvas) } }, [canvas, mode]) @@ -812,6 +823,7 @@ export default function Roof2(props) { backImg .set({ selectable: false, + opacity: 0.7, }) .sendToBack() canvas.clear() @@ -821,7 +833,7 @@ export default function Roof2(props) { } }} > - cad 파일 조정 완료 + 배경 이미지 조정 완료 + {useGoogleMapFile && ( + <> +
+

Zoom Controller : {zoom}

+ + +
+
+ +
+ + )} diff --git a/yarn.lock b/yarn.lock index 1a73ec7a..6bd3608f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5515,6 +5515,11 @@ react-dom@^18: loose-envify "^1.1.0" scheduler "^0.23.2" +react-icons@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.3.0.tgz#ccad07a30aebd40a89f8cfa7d82e466019203f1c" + integrity sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg== + react-is@^16.13.1: version "16.13.1" resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" From 2852e5eb1d4214e11d046f7ec27733266790bc1f Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 9 Sep 2024 10:10:13 +0900 Subject: [PATCH 4/4] feat: Add floor plan page and component --- src/app/[locale]/floor-plan/page.jsx | 5 +++++ src/components/floor-plan/FloorPlan.jsx | 7 +++++++ 2 files changed, 12 insertions(+) create mode 100644 src/app/[locale]/floor-plan/page.jsx create mode 100644 src/components/floor-plan/FloorPlan.jsx diff --git a/src/app/[locale]/floor-plan/page.jsx b/src/app/[locale]/floor-plan/page.jsx new file mode 100644 index 00000000..7ca0fc3e --- /dev/null +++ b/src/app/[locale]/floor-plan/page.jsx @@ -0,0 +1,5 @@ +import FloorPlan from '@/components/floor-plan/FloorPlan' + +export default function floorPlanPage() { + return +} diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx new file mode 100644 index 00000000..27e03cf6 --- /dev/null +++ b/src/components/floor-plan/FloorPlan.jsx @@ -0,0 +1,7 @@ +export default function FloorPlan() { + return ( + <> +

도면 작성 페이지

+ + ) +}