From a993a276191c9f262e9e87a4e3d728a43720ea16 Mon Sep 17 00:00:00 2001 From: dgfh0450 Date: Wed, 29 Jan 2025 20:03:54 +0900 Subject: [PATCH 01/16] =?UTF-8?q?[UNI-50]=20feat=20:=20=EC=A7=80=EB=8F=84?= =?UTF-8?q?=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=84=A4=EC=A0=95=20=EB=B0=8F?= =?UTF-8?q?=20(=EB=B9=8C=EB=94=A9,=20=EC=9C=84=ED=97=98,=20=EC=A3=BC?= =?UTF-8?q?=EC=9D=98)=20=EB=A7=88=EC=BB=A4=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EB=B0=8F=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- uniro_frontend/public/map/building.svg | 4 + uniro_frontend/public/map/caution.svg | 16 ++++ uniro_frontend/public/map/danger.svg | 16 ++++ uniro_frontend/src/App.tsx | 2 + .../src/components/map/mapMarkers.tsx | 58 ++++++++++++ .../src/data/mock/hanyangHazardEdge.ts | 10 +-- uniro_frontend/src/index.css | 4 + uniro_frontend/src/pages/map.tsx | 90 +++++++++++++++++++ 8 files changed, 195 insertions(+), 5 deletions(-) create mode 100644 uniro_frontend/public/map/building.svg create mode 100644 uniro_frontend/public/map/caution.svg create mode 100644 uniro_frontend/public/map/danger.svg create mode 100644 uniro_frontend/src/components/map/mapMarkers.tsx create mode 100644 uniro_frontend/src/pages/map.tsx diff --git a/uniro_frontend/public/map/building.svg b/uniro_frontend/public/map/building.svg new file mode 100644 index 0000000..4fc91f3 --- /dev/null +++ b/uniro_frontend/public/map/building.svg @@ -0,0 +1,4 @@ + + + + diff --git a/uniro_frontend/public/map/caution.svg b/uniro_frontend/public/map/caution.svg new file mode 100644 index 0000000..556f369 --- /dev/null +++ b/uniro_frontend/public/map/caution.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/uniro_frontend/public/map/danger.svg b/uniro_frontend/public/map/danger.svg new file mode 100644 index 0000000..5508d10 --- /dev/null +++ b/uniro_frontend/public/map/danger.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/uniro_frontend/src/App.tsx b/uniro_frontend/src/App.tsx index 26e9e4d..b41b8d0 100644 --- a/uniro_frontend/src/App.tsx +++ b/uniro_frontend/src/App.tsx @@ -3,6 +3,7 @@ import "./App.css"; import Demo from "./pages/demo"; import LandingPage from "./pages/landing"; import UniversitySearchPage from "./pages/search"; +import MapPage from "./pages/map"; function App() { return ( @@ -10,6 +11,7 @@ function App() { } /> } /> } /> + } /> ); } diff --git a/uniro_frontend/src/components/map/mapMarkers.tsx b/uniro_frontend/src/components/map/mapMarkers.tsx new file mode 100644 index 0000000..33492b7 --- /dev/null +++ b/uniro_frontend/src/components/map/mapMarkers.tsx @@ -0,0 +1,58 @@ +export function buildingMarkerContent({ title }: { title: string }): HTMLElement { + const container = document.createElement("div"); + container.className = "translate-marker flex flex-col items-center space-y-[7px]"; + + const markerImage = document.createElement("img"); + markerImage.src = "/public/map/building.svg"; + + const markerTitle = document.createElement("p"); + markerTitle.innerText = title; + markerTitle.className = "py-1 px-3 text-kor-caption font-medium text-gray-100 bg-gray-900 text-center rounded-200"; + + container.appendChild(markerImage); + container.appendChild(markerTitle); + + return container; +} + +export function cautionMarkerContent(factors?: string[]): HTMLElement { + const container = document.createElement("div"); + container.className = "translate-marker flex flex-col items-center space-y-[7px]"; + + if (factors) { + const markerFactor = document.createElement("p"); + markerFactor.innerText = factors[0]; + markerFactor.className = + "h-[38px] py-2 px-4 mb-2 text-kor-body3 font-semibold text-gray-100 bg-system-orange text-center rounded-200"; + container.classList.add("translate-y-[-46px]"); + container.appendChild(markerFactor); + } + + const markerImage = document.createElement("img"); + markerImage.src = "/public/map/caution.svg"; + + container.appendChild(markerImage); + + return container; +} + +export function dangerMarkerContent(factors?: string[]): HTMLElement { + const container = document.createElement("div"); + container.className = "translate-marker flex flex-col items-center space-y-[7px]"; + + if (factors) { + const markerFactor = document.createElement("p"); + markerFactor.innerText = factors[0]; + markerFactor.className = + "h-[38px] py-2 px-4 mb-2 text-kor-body3 font-semibold text-gray-100 bg-system-red text-center rounded-200"; + container.classList.add("translate-y-[-46px]"); + container.appendChild(markerFactor); + } + + const markerImage = document.createElement("img"); + markerImage.src = "/public/map/danger.svg"; + + container.appendChild(markerImage); + + return container; +} diff --git a/uniro_frontend/src/data/mock/hanyangHazardEdge.ts b/uniro_frontend/src/data/mock/hanyangHazardEdge.ts index e9652bd..0cd4e67 100644 --- a/uniro_frontend/src/data/mock/hanyangHazardEdge.ts +++ b/uniro_frontend/src/data/mock/hanyangHazardEdge.ts @@ -17,11 +17,11 @@ const nodes: CustomNode[] = [ ]; const edges: HazardEdge[] = [ - createHazardEdge("path0", nodes[0], nodes[1], ["도로에 균열이 있어요"], []), - createHazardEdge("path1", nodes[2], nodes[3], [], ["계단이 있어요"]), - createHazardEdge("path2", nodes[4], nodes[5], ["낮은 턱이 있어요"], []), - createHazardEdge("path3", nodes[6], nodes[7], [], ["경사가 높아요"]), - createHazardEdge("path4", nodes[8], nodes[9], ["낮은 비탈길이 있어요"], []), + createHazardEdge("path0", nodes[0], nodes[1], ["도로에 균열이 있어요"]), + createHazardEdge("path1", nodes[2], nodes[3], undefined, ["계단이 있어요"]), + createHazardEdge("path2", nodes[4], nodes[5], ["낮은 턱이 있어요"]), + createHazardEdge("path3", nodes[6], nodes[7], undefined, ["경사가 높아요"]), + createHazardEdge("path4", nodes[8], nodes[9], ["낮은 비탈길이 있어요"]), ]; export const mockHazardEdges = edges; diff --git a/uniro_frontend/src/index.css b/uniro_frontend/src/index.css index 0dadffa..601311e 100644 --- a/uniro_frontend/src/index.css +++ b/uniro_frontend/src/index.css @@ -123,3 +123,7 @@ --text-eng-caption: 12px; --text-eng-caption--line-height: 160%; } + +@utility translate-marker { + transform: translateY(calc(100% - 10px)); +} diff --git a/uniro_frontend/src/pages/map.tsx b/uniro_frontend/src/pages/map.tsx new file mode 100644 index 0000000..1e8b2f5 --- /dev/null +++ b/uniro_frontend/src/pages/map.tsx @@ -0,0 +1,90 @@ +import { useEffect, useState } from "react"; +import useMap from "../hooks/useMap"; +import { buildings } from "../data/mock/hanyangBuildings"; +import { buildingMarkerContent, cautionMarkerContent, dangerMarkerContent } from "../components/map/mapMarkers"; +import { mockHazardEdges } from "../data/mock/hanyangHazardEdge"; + +type MarkerTypes = "building" | "caution" | "danger"; + +export default function MapPage() { + const { mapRef, map, AdvancedMarker } = useMap(); + const [selectedMarker, setSelectedMarker] = useState<{ + type: MarkerTypes; + element: google.maps.marker.AdvancedMarkerElement; + }>(); + + const addBuildings = () => { + if (AdvancedMarker === null) return; + for (const building of buildings) { + const { id, lat, lng, buildingName } = building; + + const newMarker = new AdvancedMarker({ + map: map, + position: { lat, lng }, + content: buildingMarkerContent({ title: buildingName }), + }); + + newMarker.addListener("click", () => { + alert(`${id} - ${buildingName}`); + }); + } + }; + + const addHazardMarker = () => { + if (AdvancedMarker === null) return; + for (const edge of mockHazardEdges) { + const { id, startNode, endNode, dangerFactors, cautionFactors } = edge; + if (dangerFactors) { + const dangerMarker = new AdvancedMarker({ + map: map, + position: { + lat: (startNode.lat + endNode.lat) / 2, + lng: (startNode.lng + endNode.lng) / 2, + }, + content: dangerMarkerContent(), + }); + dangerMarker.addListener("click", () => { + dangerMarker.content = dangerMarkerContent(dangerFactors); + setSelectedMarker({ type: "danger", element: dangerMarker }); + }); + } else if (cautionFactors) { + const cautionMarker = new AdvancedMarker({ + map: map, + position: { + lat: (startNode.lat + endNode.lat) / 2, + lng: (startNode.lng + endNode.lng) / 2, + }, + content: cautionMarkerContent(), + }); + cautionMarker.addListener("click", () => { + cautionMarker.content = cautionMarkerContent(cautionFactors); + setSelectedMarker({ type: "caution", element: cautionMarker }); + }); + } + } + }; + + useEffect(() => { + if (map !== null) { + map.addListener("click", (e: unknown) => { + console.log(e); + setSelectedMarker((marker) => { + if (marker) { + const { type, element } = marker; + if (type === "caution") element.content = cautionMarkerContent(); + else if (type === "danger") element.content = dangerMarkerContent(); + } + return undefined; + }); + }); + addBuildings(); + addHazardMarker(); + } + }, [map]); + + return ( +
+
+
+ ); +} From a72400a040dc111a4c8d6d82161ea4a42bbdb1d4 Mon Sep 17 00:00:00 2001 From: dgfh0450 Date: Thu, 30 Jan 2025 14:59:21 +0900 Subject: [PATCH 02/16] =?UTF-8?q?[UNI-55]=20feat=20:=20react-spring-bottom?= =?UTF-8?q?-sheet=20=EC=84=A4=EC=B9=98=20=EB=B0=8F=20=EC=9E=A5=EC=86=8C=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=EB=B0=94=ED=85=80=EC=8B=9C=ED=8A=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- uniro_frontend/package-lock.json | 249 +++++++++++++++++- uniro_frontend/package.json | 1 + uniro_frontend/public/icons/call-thick.svg | 3 + .../public/icons/location-thick.svg | 4 + .../src/components/map/mapBottomSheet.tsx | 38 +++ uniro_frontend/src/main.tsx | 8 +- .../map/initializer/googleMapInitializer.ts | 6 +- uniro_frontend/src/pages/map.tsx | 191 ++++++++------ 8 files changed, 406 insertions(+), 94 deletions(-) create mode 100644 uniro_frontend/public/icons/call-thick.svg create mode 100644 uniro_frontend/public/icons/location-thick.svg create mode 100644 uniro_frontend/src/components/map/mapBottomSheet.tsx diff --git a/uniro_frontend/package-lock.json b/uniro_frontend/package-lock.json index 9fb6f47..70abb15 100644 --- a/uniro_frontend/package-lock.json +++ b/uniro_frontend/package-lock.json @@ -13,6 +13,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-router": "^7.1.3", + "react-spring-bottom-sheet": "^3.4.1", "tailwindcss": "^4.0.0" }, "devDependencies": { @@ -273,6 +274,18 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.7.tgz", + "integrity": "sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", @@ -997,6 +1010,12 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@juggle/resize-observer": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz", + "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==", + "license": "Apache-2.0" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1879,6 +1898,12 @@ "@types/react": "^18.0.0" } }, + "node_modules/@types/warning": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", + "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==", + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.21.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.21.0.tgz", @@ -2350,6 +2375,12 @@ "dev": true, "license": "MIT" }, + "node_modules/body-scroll-lock": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/body-scroll-lock/-/body-scroll-lock-3.1.5.tgz", + "integrity": "sha512-Yi1Xaml0EvNA0OYWxXiYNqY24AfWkbA6w5vxE7GWxtKfzIbZM+Qw+aSmkgsbWzbHiy/RCSkUZBplVxTA+E4jJg==", + "license": "MIT" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2552,6 +2583,15 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/cosmiconfig": { "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", @@ -2579,15 +2619,6 @@ } } }, - "node_modules/cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3446,6 +3477,15 @@ "dev": true, "license": "ISC" }, + "node_modules/focus-trap": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.9.4.tgz", + "integrity": "sha512-v2NTsZe2FF59Y+sDykKY+XjqZ0cPfhq/hikWVL88BqLivnNiEffAsac6rP6H45ff9wG9LL5ToiDqrLEP9GX9mw==", + "license": "MIT", + "dependencies": { + "tabbable": "^5.3.3" + } + }, "node_modules/for-each": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.4.tgz", @@ -4729,7 +4769,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5069,7 +5108,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", @@ -5137,7 +5175,6 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true, "license": "MIT" }, "node_modules/react-refresh": { @@ -5174,6 +5211,127 @@ } } }, + "node_modules/react-spring": { + "version": "8.0.27", + "resolved": "https://registry.npmjs.org/react-spring/-/react-spring-8.0.27.tgz", + "integrity": "sha512-nDpWBe3ZVezukNRandTeLSPcwwTMjNVu1IDq9qA/AMiUqHuRN4BeSWvKr3eIxxg1vtiYiOLy4FqdfCP5IoP77g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "prop-types": "^15.5.8" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + } + }, + "node_modules/react-spring-bottom-sheet": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/react-spring-bottom-sheet/-/react-spring-bottom-sheet-3.4.1.tgz", + "integrity": "sha512-yDFqiPMm/fjefjnOe6Q9zxccbCl6HMUKsK5bWgfGHJIj4zmXVKio5d4icQvmOLuwpuCA2pwv4J6nGWS6fUZidQ==", + "license": "MIT", + "dependencies": { + "@juggle/resize-observer": "^3.2.0", + "@reach/portal": "^0.13.0", + "@xstate/react": "^1.2.0", + "body-scroll-lock": "^3.1.5", + "focus-trap": "^6.2.2", + "react-spring": "^8.0.27", + "react-use-gesture": "^8.0.1", + "xstate": "^4.15.1" + }, + "peerDependencies": { + "react": "^16.14.0 || 17 || 18" + } + }, + "node_modules/react-spring-bottom-sheet/node_modules/@reach/portal": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/@reach/portal/-/portal-0.13.2.tgz", + "integrity": "sha512-g74BnCdtuTGthzzHn2cWW+bcyIYb0iIE/yRsm89i8oNzNgpopbkh9UY8TPbhNlys52h7U60s4kpRTmcq+JqsTA==", + "license": "MIT", + "dependencies": { + "@reach/utils": "0.13.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": "^16.8.0 || 17.x", + "react-dom": "^16.8.0 || 17.x" + } + }, + "node_modules/react-spring-bottom-sheet/node_modules/@reach/portal/node_modules/@reach/utils": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/@reach/utils/-/utils-0.13.2.tgz", + "integrity": "sha512-3ir6cN60zvUrwjOJu7C6jec/samqAeyAB12ZADK+qjnmQPdzSYldrFWwDVV5H0WkhbYXR3uh+eImu13hCetNPQ==", + "license": "MIT", + "dependencies": { + "@types/warning": "^3.0.0", + "tslib": "^2.1.0", + "warning": "^4.0.3" + }, + "peerDependencies": { + "react": "^16.8.0 || 17.x", + "react-dom": "^16.8.0 || 17.x" + } + }, + "node_modules/react-spring-bottom-sheet/node_modules/@xstate/react": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@xstate/react/-/react-1.6.3.tgz", + "integrity": "sha512-NCUReRHPGvvCvj2yLZUTfR0qVp6+apc8G83oXSjN4rl89ZjyujiKrTff55bze/HrsvCsP/sUJASf2n0nzMF1KQ==", + "license": "MIT", + "dependencies": { + "use-isomorphic-layout-effect": "^1.0.0", + "use-subscription": "^1.3.0" + }, + "peerDependencies": { + "@xstate/fsm": "^1.0.0", + "react": "^16.8.0 || ^17.0.0", + "xstate": "^4.11.0" + }, + "peerDependenciesMeta": { + "@xstate/fsm": { + "optional": true + }, + "xstate": { + "optional": true + } + } + }, + "node_modules/react-spring-bottom-sheet/node_modules/react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + }, + "peerDependencies": { + "react": "17.0.2" + } + }, + "node_modules/react-spring-bottom-sheet/node_modules/scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "node_modules/react-use-gesture": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/react-use-gesture/-/react-use-gesture-8.0.1.tgz", + "integrity": "sha512-CXzUNkulUdgouaAlvAsC5ZVo0fi9KGSBSk81WrE4kOIcJccpANe9zZkAYr5YZZhqpicIFxitsrGVS4wmoMun9A==", + "deprecated": "This package is no longer maintained. Please use @use-gesture/react instead", + "license": "MIT", + "peerDependencies": { + "react": ">= 16.8.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -5197,6 +5355,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -5728,6 +5892,12 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/tabbable": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", + "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==", + "license": "MIT" + }, "node_modules/tailwindcss": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0.tgz", @@ -5773,7 +5943,6 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, "license": "0BSD" }, "node_modules/turbo-stream": { @@ -5970,6 +6139,41 @@ "punycode": "^2.1.0" } }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.0.tgz", + "integrity": "sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-subscription": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.10.0.tgz", + "integrity": "sha512-ZRLhsMSjz01kBA8106zdzEjttJ20Rauscf0umwVRjaz8idRfoddOnAVH6VEBdu55eCq02L1g+j3NcleAar1aWw==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", + "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/vite": { "version": "6.0.11", "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.11.tgz", @@ -6056,6 +6260,15 @@ "vite": ">=2.6.0" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6170,6 +6383,16 @@ "node": ">=0.10.0" } }, + "node_modules/xstate": { + "version": "4.38.3", + "resolved": "https://registry.npmjs.org/xstate/-/xstate-4.38.3.tgz", + "integrity": "sha512-SH7nAaaPQx57dx6qvfcIgqKRXIh4L0A1iYEqim4s1u7c9VoCgzZc+63FY90AKU4ZzOC2cfJzTnpO4zK7fCUzzw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/xstate" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/uniro_frontend/package.json b/uniro_frontend/package.json index 6d9da40..b749016 100644 --- a/uniro_frontend/package.json +++ b/uniro_frontend/package.json @@ -15,6 +15,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-router": "^7.1.3", + "react-spring-bottom-sheet": "^3.4.1", "tailwindcss": "^4.0.0" }, "devDependencies": { diff --git a/uniro_frontend/public/icons/call-thick.svg b/uniro_frontend/public/icons/call-thick.svg new file mode 100644 index 0000000..adbbe90 --- /dev/null +++ b/uniro_frontend/public/icons/call-thick.svg @@ -0,0 +1,3 @@ + + + diff --git a/uniro_frontend/public/icons/location-thick.svg b/uniro_frontend/public/icons/location-thick.svg new file mode 100644 index 0000000..06f8748 --- /dev/null +++ b/uniro_frontend/public/icons/location-thick.svg @@ -0,0 +1,4 @@ + + + + diff --git a/uniro_frontend/src/components/map/mapBottomSheet.tsx b/uniro_frontend/src/components/map/mapBottomSheet.tsx new file mode 100644 index 0000000..9587d98 --- /dev/null +++ b/uniro_frontend/src/components/map/mapBottomSheet.tsx @@ -0,0 +1,38 @@ +import { SelectedMarkerTypes } from "../../pages/map"; +import Button from "../customButton"; +import Call from "/public/icons/call-thick.svg?react"; +import Location from "/public/icons/location-thick.svg?react"; + +interface MapBottomSheetProps { + building: SelectedMarkerTypes; + buttonText: string; + onClick: () => void; +} + +export default function MapBottomSheet({ building, buttonText, onClick }: MapBottomSheetProps) { + if (building.property === undefined) return; + + const { id, lng, lat, isCore, buildingName, buildingImageUrl, phoneNumber, address } = building.property; + + return ( +
+
+ +
+

{buildingName}

+

+ + {address} +

+

+ + {phoneNumber} +

+
+
+ +
+ ); +} diff --git a/uniro_frontend/src/main.tsx b/uniro_frontend/src/main.tsx index 8e96476..bea4082 100644 --- a/uniro_frontend/src/main.tsx +++ b/uniro_frontend/src/main.tsx @@ -5,9 +5,7 @@ import App from "./App.tsx"; import { BrowserRouter } from "react-router"; createRoot(document.getElementById("root")!).render( - - - - - , + + + , ); diff --git a/uniro_frontend/src/map/initializer/googleMapInitializer.ts b/uniro_frontend/src/map/initializer/googleMapInitializer.ts index edfb317..04b1ecc 100644 --- a/uniro_frontend/src/map/initializer/googleMapInitializer.ts +++ b/uniro_frontend/src/map/initializer/googleMapInitializer.ts @@ -20,7 +20,9 @@ export const initializeMap = async (mapElement: HTMLElement | null): Promise void, +) { + const newMarker = new AdvancedMarker({ + map: map, + position: position, + content: content, + }); + + newMarker.addListener("click", clickCallback); + + return newMarker; +} export default function MapPage() { - const { mapRef, map, AdvancedMarker } = useMap(); - const [selectedMarker, setSelectedMarker] = useState<{ - type: MarkerTypes; - element: google.maps.marker.AdvancedMarkerElement; - }>(); + const { mapRef, map, AdvancedMarker } = useMap(); + const [selectedMarker, setSelectedMarker] = useState(); + const bottomSheetRef = useRef(null); + const [sheetOpen, setSheetOpen] = useState(false); + + const initMap = () => { + if (map === null) return; + map.addListener("click", (e: unknown) => { + setSelectedMarker((marker) => { + if (marker) { + const { type, element } = marker; - const addBuildings = () => { - if (AdvancedMarker === null) return; - for (const building of buildings) { - const { id, lat, lng, buildingName } = building; + switch (type) { + case "caution": + element.content = cautionMarkerContent(); + break; + case "danger": + element.content = dangerMarkerContent(); + break; + case "building": + setSheetOpen(false); + break; + } + } + return undefined; + }); + }); + }; - const newMarker = new AdvancedMarker({ - map: map, - position: { lat, lng }, - content: buildingMarkerContent({ title: buildingName }), - }); + const addBuildings = () => { + if (AdvancedMarker === null || map === null) return; + for (const building of buildings) { + const { id, lat, lng, buildingName } = building; - newMarker.addListener("click", () => { - alert(`${id} - ${buildingName}`); - }); - } - }; + const buildingMarker = createAdvancedMarker( + AdvancedMarker, + map, + new google.maps.LatLng(lat, lng), + buildingMarkerContent({ title: buildingName }), + () => { + setSheetOpen(true); + map?.setOptions({ + center: { lat, lng }, + zoom: 19, + }); + setSelectedMarker({ type: "building", element: buildingMarker, property: building }); + }, + ); + } + }; - const addHazardMarker = () => { - if (AdvancedMarker === null) return; - for (const edge of mockHazardEdges) { - const { id, startNode, endNode, dangerFactors, cautionFactors } = edge; - if (dangerFactors) { - const dangerMarker = new AdvancedMarker({ - map: map, - position: { - lat: (startNode.lat + endNode.lat) / 2, - lng: (startNode.lng + endNode.lng) / 2, - }, - content: dangerMarkerContent(), - }); - dangerMarker.addListener("click", () => { - dangerMarker.content = dangerMarkerContent(dangerFactors); - setSelectedMarker({ type: "danger", element: dangerMarker }); - }); - } else if (cautionFactors) { - const cautionMarker = new AdvancedMarker({ - map: map, - position: { - lat: (startNode.lat + endNode.lat) / 2, - lng: (startNode.lng + endNode.lng) / 2, - }, - content: cautionMarkerContent(), - }); - cautionMarker.addListener("click", () => { - cautionMarker.content = cautionMarkerContent(cautionFactors); - setSelectedMarker({ type: "caution", element: cautionMarker }); - }); - } - } - }; + const addHazardMarker = () => { + if (AdvancedMarker === null || map === null) return; + for (const edge of mockHazardEdges) { + const { id, startNode, endNode, dangerFactors, cautionFactors } = edge; + const hazardMarker = createAdvancedMarker( + AdvancedMarker, + map, + new google.maps.LatLng({ + lat: (startNode.lat + endNode.lat) / 2, + lng: (startNode.lng + endNode.lng) / 2, + }), + dangerFactors ? dangerMarkerContent() : cautionMarkerContent(), + () => { + hazardMarker.content = dangerFactors + ? dangerMarkerContent(dangerFactors) + : cautionMarkerContent(cautionFactors); + setSelectedMarker({ type: dangerFactors ? "danger" : "caution", element: hazardMarker }); + }, + ); + } + }; - useEffect(() => { - if (map !== null) { - map.addListener("click", (e: unknown) => { - console.log(e); - setSelectedMarker((marker) => { - if (marker) { - const { type, element } = marker; - if (type === "caution") element.content = cautionMarkerContent(); - else if (type === "danger") element.content = dangerMarkerContent(); - } - return undefined; - }); - }); - addBuildings(); - addHazardMarker(); - } - }, [map]); + useEffect(() => { + initMap(); + addBuildings(); + addHazardMarker(); + }, [map]); - return ( -
-
-
- ); + return ( +
+
+ minHeight} + > + {selectedMarker && ( + {}} buttonText="출발지 설정" building={selectedMarker} /> + )} + +
+ ); } From 4f4c20140bdd0c5489e86341e3ab831d02f9f360 Mon Sep 17 00:00:00 2001 From: dgfh0450 Date: Thu, 30 Jan 2025 16:18:35 +0900 Subject: [PATCH 03/16] =?UTF-8?q?[UNI-50]=20feat=20:=20=EC=A7=80=EB=8F=84?= =?UTF-8?q?=20=EA=B2=BD=EB=A1=9C=20=EA=B2=80=EC=83=89=20Input=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- uniro_frontend/src/assets/map/destination.svg | 4 +++ uniro_frontend/src/assets/map/origin.svg | 4 +++ .../src/components/map/routeSearchInput.tsx | 30 +++++++++++++++++++ uniro_frontend/src/pages/demo.tsx | 16 ++++++++++ 4 files changed, 54 insertions(+) create mode 100644 uniro_frontend/src/assets/map/destination.svg create mode 100644 uniro_frontend/src/assets/map/origin.svg create mode 100644 uniro_frontend/src/components/map/routeSearchInput.tsx diff --git a/uniro_frontend/src/assets/map/destination.svg b/uniro_frontend/src/assets/map/destination.svg new file mode 100644 index 0000000..7b1ffe8 --- /dev/null +++ b/uniro_frontend/src/assets/map/destination.svg @@ -0,0 +1,4 @@ + + + + diff --git a/uniro_frontend/src/assets/map/origin.svg b/uniro_frontend/src/assets/map/origin.svg new file mode 100644 index 0000000..526e804 --- /dev/null +++ b/uniro_frontend/src/assets/map/origin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/uniro_frontend/src/components/map/routeSearchInput.tsx b/uniro_frontend/src/components/map/routeSearchInput.tsx new file mode 100644 index 0000000..9ddde1c --- /dev/null +++ b/uniro_frontend/src/components/map/routeSearchInput.tsx @@ -0,0 +1,30 @@ +import { InputHTMLAttributes, ReactNode } from "react"; +import Close from "/public/icons/close-circle.svg?react"; + +interface RouteInputProps extends InputHTMLAttributes { + placeholder: string; + children: ReactNode; + value?: string; + onCancel?: () => void; +} + +export default function RouteInput({ placeholder, children, value, onCancel }: RouteInputProps) { + return ( +
+ {children} + + {value && ( + + )} +
+ ); +} diff --git a/uniro_frontend/src/pages/demo.tsx b/uniro_frontend/src/pages/demo.tsx index 4d64dea..23d79e6 100644 --- a/uniro_frontend/src/pages/demo.tsx +++ b/uniro_frontend/src/pages/demo.tsx @@ -3,10 +3,15 @@ import Button from "../components/customButton"; import LandingButton from "../components/landingButton"; import Input from "../components/customInput"; import Map from "../component/Map"; +import RouteInput from "../components/map/routeSearchInput"; +import StartIcon from "../assets/map/origin.svg?react"; +import EndIcon from "../assets/map/destination.svg?react"; +import { useState } from "react"; export default function Demo() { const [FailModal, isFailOpen, openFail, closeFail] = useModal(); const [SuccessModal, isSuccessOpen, openSuccess, closeSuccess] = useModal(); + const [destination, setDestination] = useState("역사관"); return ( <> @@ -29,6 +34,17 @@ export default function Demo() { console.log(e); }} /> + + + + + setDestination("")} + > + +

불편한 길 제보가 완료되었습니다!

From 167d328ce7ff4940ab72b8b6329f060b6f535d5b Mon Sep 17 00:00:00 2001 From: dgfh0450 Date: Thu, 30 Jan 2025 16:19:41 +0900 Subject: [PATCH 04/16] =?UTF-8?q?[UNI-50]=20feat=20:=20=EC=A7=80=EB=8F=84?= =?UTF-8?q?=20=EB=A9=94=EC=9D=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20TopSheet?= =?UTF-8?q?=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/map/TopSheet.tsx | 24 +++++++++++++++++++ uniro_frontend/src/pages/map.tsx | 2 ++ 2 files changed, 26 insertions(+) create mode 100644 uniro_frontend/src/components/map/TopSheet.tsx diff --git a/uniro_frontend/src/components/map/TopSheet.tsx b/uniro_frontend/src/components/map/TopSheet.tsx new file mode 100644 index 0000000..f1bfddb --- /dev/null +++ b/uniro_frontend/src/components/map/TopSheet.tsx @@ -0,0 +1,24 @@ +import RouteInput from "../map/routeSearchInput"; +import OriginIcon from "../../assets/map/origin.svg?react"; +import Destination from "../../assets/map/destination.svg?react"; +import LocationIcon from "../../../public/icons/location-thick.svg?react"; +import { Link } from "react-router"; + +export default function TopSheet() { + return ( +
+

+ + 한양대학교 +

+
+ + + + + + +
+
+ ); +} diff --git a/uniro_frontend/src/pages/map.tsx b/uniro_frontend/src/pages/map.tsx index 7ddcc28..6f1ad03 100644 --- a/uniro_frontend/src/pages/map.tsx +++ b/uniro_frontend/src/pages/map.tsx @@ -7,6 +7,7 @@ import { BottomSheet, BottomSheetRef } from "react-spring-bottom-sheet"; import { Building } from "../data/types/node"; import "react-spring-bottom-sheet/dist/style.css"; import MapBottomSheet from "../components/map/mapBottomSheet"; +import TopSheet from "../components/map/TopSheet"; type MarkerTypes = "building" | "caution" | "danger"; export type SelectedMarkerTypes = { @@ -115,6 +116,7 @@ export default function MapPage() { return (
+ {!sheetOpen && }
Date: Thu, 30 Jan 2025 16:52:39 +0900 Subject: [PATCH 05/16] =?UTF-8?q?[UNI-50]=20feat=20:=20Framer-motion=20?= =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=84=A4?= =?UTF-8?q?=EC=B9=98=20=EB=B0=8F=20TopSheet=20=EC=95=A0=EB=8B=88=EB=A9=94?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- uniro_frontend/package-lock.json | 43 +++++++++++++++++++ uniro_frontend/package.json | 1 + uniro_frontend/src/assets/switch.svg | 12 ++++++ .../src/components/map/TopSheet.tsx | 35 ++++++++++----- uniro_frontend/src/pages/map.tsx | 2 +- 5 files changed, 82 insertions(+), 11 deletions(-) create mode 100644 uniro_frontend/src/assets/switch.svg diff --git a/uniro_frontend/package-lock.json b/uniro_frontend/package-lock.json index 70abb15..590f376 100644 --- a/uniro_frontend/package-lock.json +++ b/uniro_frontend/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@googlemaps/js-api-loader": "^1.16.8", "@tailwindcss/vite": "^4.0.0", + "framer-motion": "^12.0.6", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router": "^7.1.3", @@ -3502,6 +3503,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/framer-motion": { + "version": "12.0.6", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.0.6.tgz", + "integrity": "sha512-LmrXbXF6Vv5WCNmb+O/zn891VPZrH7XbsZgRLBROw6kFiP+iTK49gxTv2Ur3F0Tbw6+sy9BVtSqnWfMUpH+6nA==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.0.0", + "motion-utils": "^12.0.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -4715,6 +4743,21 @@ "node": "*" } }, + "node_modules/motion-dom": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.0.0.tgz", + "integrity": "sha512-CvYd15OeIR6kHgMdonCc1ihsaUG4MYh/wrkz8gZ3hBX/uamyZCXN9S9qJoYF03GqfTt7thTV/dxnHYX4+55vDg==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.0.0" + } + }, + "node_modules/motion-utils": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.0.0.tgz", + "integrity": "sha512-MNFiBKbbqnmvOjkPyOKgHUp3Q6oiokLkI1bEwm5QA28cxMZrv0CbbBGDNmhF6DIXsi1pCQBSs0dX8xjeER1tmA==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/uniro_frontend/package.json b/uniro_frontend/package.json index b749016..70b35bd 100644 --- a/uniro_frontend/package.json +++ b/uniro_frontend/package.json @@ -12,6 +12,7 @@ "dependencies": { "@googlemaps/js-api-loader": "^1.16.8", "@tailwindcss/vite": "^4.0.0", + "framer-motion": "^12.0.6", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router": "^7.1.3", diff --git a/uniro_frontend/src/assets/switch.svg b/uniro_frontend/src/assets/switch.svg new file mode 100644 index 0000000..a73ff97 --- /dev/null +++ b/uniro_frontend/src/assets/switch.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/uniro_frontend/src/components/map/TopSheet.tsx b/uniro_frontend/src/components/map/TopSheet.tsx index f1bfddb..9c592a0 100644 --- a/uniro_frontend/src/components/map/TopSheet.tsx +++ b/uniro_frontend/src/components/map/TopSheet.tsx @@ -2,23 +2,38 @@ import RouteInput from "../map/routeSearchInput"; import OriginIcon from "../../assets/map/origin.svg?react"; import Destination from "../../assets/map/destination.svg?react"; import LocationIcon from "../../../public/icons/location-thick.svg?react"; +import SwitchIcon from "../../assets/switch.svg?react"; import { Link } from "react-router"; +import { motion } from "framer-motion"; -export default function TopSheet() { +export default function TopSheet({ open }: { open: boolean }) { return ( -
+

한양대학교

-
- - - - - - +
+
+ + + + + + +
+
+ +
-
+
); } diff --git a/uniro_frontend/src/pages/map.tsx b/uniro_frontend/src/pages/map.tsx index 6f1ad03..409e5c6 100644 --- a/uniro_frontend/src/pages/map.tsx +++ b/uniro_frontend/src/pages/map.tsx @@ -116,7 +116,7 @@ export default function MapPage() { return (
- {!sheetOpen && } +
Date: Thu, 30 Jan 2025 17:25:25 +0900 Subject: [PATCH 06/16] =?UTF-8?q?[UNI-50]=20feat=20:=20=EC=A7=80=EB=8F=84?= =?UTF-8?q?=20=EB=A9=94=EC=9D=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=ED=95=98?= =?UTF-8?q?=EB=8B=A8=20=ED=94=8C=EB=A1=9C=ED=8C=85=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?(=EC=A0=9C=EB=B3=B4=ED=95=98=EA=B8=B0,=20=EC=9C=84=ED=97=98,=20?= =?UTF-8?q?=EC=A3=BC=EC=9D=98=20=ED=86=A0=EA=B8=80)=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- uniro_frontend/src/assets/caution.svg | 4 +++ uniro_frontend/src/assets/danger.svg | 4 +++ uniro_frontend/src/assets/report.svg | 3 +++ .../src/components/map/floatingButtons.tsx | 27 +++++++++++++++++++ .../src/components/map/reportButton.tsx | 14 ++++++++++ uniro_frontend/src/index.css | 1 + uniro_frontend/src/pages/demo.tsx | 17 +++++++++++- uniro_frontend/src/pages/map.tsx | 9 +++++++ 8 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 uniro_frontend/src/assets/caution.svg create mode 100644 uniro_frontend/src/assets/danger.svg create mode 100644 uniro_frontend/src/assets/report.svg create mode 100644 uniro_frontend/src/components/map/floatingButtons.tsx create mode 100644 uniro_frontend/src/components/map/reportButton.tsx diff --git a/uniro_frontend/src/assets/caution.svg b/uniro_frontend/src/assets/caution.svg new file mode 100644 index 0000000..53a8adc --- /dev/null +++ b/uniro_frontend/src/assets/caution.svg @@ -0,0 +1,4 @@ + + + + diff --git a/uniro_frontend/src/assets/danger.svg b/uniro_frontend/src/assets/danger.svg new file mode 100644 index 0000000..0d1362d --- /dev/null +++ b/uniro_frontend/src/assets/danger.svg @@ -0,0 +1,4 @@ + + + + diff --git a/uniro_frontend/src/assets/report.svg b/uniro_frontend/src/assets/report.svg new file mode 100644 index 0000000..ba70ed9 --- /dev/null +++ b/uniro_frontend/src/assets/report.svg @@ -0,0 +1,3 @@ + + + diff --git a/uniro_frontend/src/components/map/floatingButtons.tsx b/uniro_frontend/src/components/map/floatingButtons.tsx new file mode 100644 index 0000000..77bc2e3 --- /dev/null +++ b/uniro_frontend/src/components/map/floatingButtons.tsx @@ -0,0 +1,27 @@ +import React from "react"; +import DangerIcon from "../../assets/danger.svg?react"; +import CautionIcon from "../../assets/caution.svg?react"; + +interface ToggleButtonProps { + isActive: boolean; +} + +export function DangerToggleButton({ isActive }: ToggleButtonProps) { + return ( + + ); +} + +export function CautionToggleButton({ isActive }: ToggleButtonProps) { + return ( + + ); +} diff --git a/uniro_frontend/src/components/map/reportButton.tsx b/uniro_frontend/src/components/map/reportButton.tsx new file mode 100644 index 0000000..5944561 --- /dev/null +++ b/uniro_frontend/src/components/map/reportButton.tsx @@ -0,0 +1,14 @@ +import { Link } from "react-router"; +import ReportIcon from "../../assets/report.svg?react"; + +export default function ReportButton() { + return ( + + 제보하기 + + + ); +} diff --git a/uniro_frontend/src/index.css b/uniro_frontend/src/index.css index 601311e..1753e19 100644 --- a/uniro_frontend/src/index.css +++ b/uniro_frontend/src/index.css @@ -43,6 +43,7 @@ font-family: "SF Pro Display", "AppleSDGothicNeo"; outline: none; --webkit-scrollbar-width: none; + box-sizing: border-box; } *::-webkit-scrollbar { diff --git a/uniro_frontend/src/pages/demo.tsx b/uniro_frontend/src/pages/demo.tsx index 23d79e6..460a788 100644 --- a/uniro_frontend/src/pages/demo.tsx +++ b/uniro_frontend/src/pages/demo.tsx @@ -7,6 +7,8 @@ import RouteInput from "../components/map/routeSearchInput"; import StartIcon from "../assets/map/origin.svg?react"; import EndIcon from "../assets/map/destination.svg?react"; import { useState } from "react"; +import ReportButton from "../components/map/reportButton"; +import { CautionToggleButton, DangerToggleButton } from "../components/map/floatingButtons"; export default function Demo() { const [FailModal, isFailOpen, openFail, closeFail] = useModal(); @@ -15,7 +17,7 @@ export default function Demo() { return ( <> -
+
+
+ +
+ + +
+ +
+ + +
+
+
+
+ +
+
+ + +
Date: Thu, 30 Jan 2025 17:41:54 +0900 Subject: [PATCH 07/16] =?UTF-8?q?[UNI-50]=20feat=20:=20=EC=A7=80=EB=8F=84?= =?UTF-8?q?=20=EB=A9=94=EC=9D=B8=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=9C=84?= =?UTF-8?q?=ED=97=98,=20=EC=A3=BC=EC=9D=98=20=EC=9A=94=EC=86=8C=20?= =?UTF-8?q?=ED=86=A0=EA=B8=80=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/map/floatingButtons.tsx | 7 +++- uniro_frontend/src/pages/demo.tsx | 8 ++-- uniro_frontend/src/pages/map.tsx | 40 ++++++++++++++++++- 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/uniro_frontend/src/components/map/floatingButtons.tsx b/uniro_frontend/src/components/map/floatingButtons.tsx index 77bc2e3..51d9f10 100644 --- a/uniro_frontend/src/components/map/floatingButtons.tsx +++ b/uniro_frontend/src/components/map/floatingButtons.tsx @@ -4,11 +4,13 @@ import CautionIcon from "../../assets/caution.svg?react"; interface ToggleButtonProps { isActive: boolean; + onClick: () => void; } -export function DangerToggleButton({ isActive }: ToggleButtonProps) { +export function DangerToggleButton({ isActive, onClick }: ToggleButtonProps) { return (
- - + +
Date: Thu, 30 Jan 2025 18:33:16 +0900 Subject: [PATCH 08/16] =?UTF-8?q?[UNI-50]=20feat=20:=20Marker=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=EC=9D=B4=ED=9B=84=20=EC=B6=9C=EB=B0=9C=EC=A7=80,?= =?UTF-8?q?=20=EB=8F=84=EC=B0=A9=EC=A7=80=20=EC=84=A4=EC=A0=95=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- uniro_frontend/package-lock.json | 38 +++++++++++-- uniro_frontend/package.json | 3 +- .../src/components/map/TopSheet.tsx | 18 +++++-- .../src/components/map/mapBottomSheet.tsx | 43 ++++++++++++++- uniro_frontend/src/hooks/useSearchRoute.ts | 20 +++++++ uniro_frontend/src/pages/map.tsx | 53 ++++++++++++++++--- 6 files changed, 159 insertions(+), 16 deletions(-) create mode 100644 uniro_frontend/src/hooks/useSearchRoute.ts diff --git a/uniro_frontend/package-lock.json b/uniro_frontend/package-lock.json index 590f376..d8e1fb4 100644 --- a/uniro_frontend/package-lock.json +++ b/uniro_frontend/package-lock.json @@ -15,7 +15,8 @@ "react-dom": "^18.3.1", "react-router": "^7.1.3", "react-spring-bottom-sheet": "^3.4.1", - "tailwindcss": "^4.0.0" + "tailwindcss": "^4.0.0", + "zustand": "^5.0.3" }, "devDependencies": { "@eslint/js": "^9.17.0", @@ -1875,14 +1876,14 @@ "version": "15.7.14", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.18", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz", "integrity": "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -2639,7 +2640,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/data-view-buffer": { @@ -6455,6 +6456,35 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zustand": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.3.tgz", + "integrity": "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } } } } diff --git a/uniro_frontend/package.json b/uniro_frontend/package.json index 70b35bd..c3cbea7 100644 --- a/uniro_frontend/package.json +++ b/uniro_frontend/package.json @@ -17,7 +17,8 @@ "react-dom": "^18.3.1", "react-router": "^7.1.3", "react-spring-bottom-sheet": "^3.4.1", - "tailwindcss": "^4.0.0" + "tailwindcss": "^4.0.0", + "zustand": "^5.0.3" }, "devDependencies": { "@eslint/js": "^9.17.0", diff --git a/uniro_frontend/src/components/map/TopSheet.tsx b/uniro_frontend/src/components/map/TopSheet.tsx index 9c592a0..1ece4e8 100644 --- a/uniro_frontend/src/components/map/TopSheet.tsx +++ b/uniro_frontend/src/components/map/TopSheet.tsx @@ -5,8 +5,12 @@ import LocationIcon from "../../../public/icons/location-thick.svg?react"; import SwitchIcon from "../../assets/switch.svg?react"; import { Link } from "react-router"; import { motion } from "framer-motion"; +import useSearchRoute from "../../hooks/useSearchRoute"; +import { useEffect } from "react"; export default function TopSheet({ open }: { open: boolean }) { + const { origin, setOrigin, destination, setDestination, switchBuilding } = useSearchRoute(); + return (
- + setOrigin(undefined)} + > - + setDestination(undefined)} + >
-
diff --git a/uniro_frontend/src/components/map/mapBottomSheet.tsx b/uniro_frontend/src/components/map/mapBottomSheet.tsx index 9587d98..cafa43a 100644 --- a/uniro_frontend/src/components/map/mapBottomSheet.tsx +++ b/uniro_frontend/src/components/map/mapBottomSheet.tsx @@ -3,13 +3,13 @@ import Button from "../customButton"; import Call from "/public/icons/call-thick.svg?react"; import Location from "/public/icons/location-thick.svg?react"; -interface MapBottomSheetProps { +interface MapBottomSheetFromListProps { building: SelectedMarkerTypes; buttonText: string; onClick: () => void; } -export default function MapBottomSheet({ building, buttonText, onClick }: MapBottomSheetProps) { +export function MapBottomSheetFromList({ building, buttonText, onClick }: MapBottomSheetFromListProps) { if (building.property === undefined) return; const { id, lng, lat, isCore, buildingName, buildingImageUrl, phoneNumber, address } = building.property; @@ -36,3 +36,42 @@ export default function MapBottomSheet({ building, buttonText, onClick }: MapBot
); } + +interface MapBottomSheetProps { + building: SelectedMarkerTypes; + onClickLeft: () => void; + onClickRight: () => void; +} + +export function MapBottomSheetFromMarker({ building, onClickLeft, onClickRight }: MapBottomSheetProps) { + if (building.property === undefined) return; + + const { id, lng, lat, isCore, buildingName, buildingImageUrl, phoneNumber, address } = building.property; + + return ( +
+
+ +
+

{buildingName}

+

+ + {address} +

+

+ + {phoneNumber} +

+
+
+
+ + +
+
+ ); +} diff --git a/uniro_frontend/src/hooks/useSearchRoute.ts b/uniro_frontend/src/hooks/useSearchRoute.ts new file mode 100644 index 0000000..660ea29 --- /dev/null +++ b/uniro_frontend/src/hooks/useSearchRoute.ts @@ -0,0 +1,20 @@ +import { create } from "zustand"; +import { Building } from "../data/types/node"; + +interface RouteStore { + origin: Building | undefined; + setOrigin: (origin: Building | undefined) => void; + destination: Building | undefined; + setDestination: (destination: Building | undefined) => void; + switchBuilding: () => void; +} + +const useSearchRoute = create((set) => ({ + origin: undefined, + setOrigin: (newOrigin: Building | undefined) => set(() => ({ origin: newOrigin })), + destination: undefined, + setDestination: (newDestination: Building | undefined) => set(() => ({ destination: newDestination })), + switchBuilding: () => set(({ origin, destination }) => ({ origin: destination, destination: origin })), +})); + +export default useSearchRoute; diff --git a/uniro_frontend/src/pages/map.tsx b/uniro_frontend/src/pages/map.tsx index 5b89580..000f7ec 100644 --- a/uniro_frontend/src/pages/map.tsx +++ b/uniro_frontend/src/pages/map.tsx @@ -6,16 +6,18 @@ import { mockHazardEdges } from "../data/mock/hanyangHazardEdge"; import { BottomSheet, BottomSheetRef } from "react-spring-bottom-sheet"; import { Building } from "../data/types/node"; import "react-spring-bottom-sheet/dist/style.css"; -import MapBottomSheet from "../components/map/mapBottomSheet"; +import { MapBottomSheetFromList, MapBottomSheetFromMarker } from "../components/map/mapBottomSheet"; import TopSheet from "../components/map/TopSheet"; import { CautionToggleButton, DangerToggleButton } from "../components/map/floatingButtons"; import ReportButton from "../components/map/reportButton"; +import useSearchRoute from "../hooks/useSearchRoute"; type MarkerTypes = "building" | "caution" | "danger"; export type SelectedMarkerTypes = { type: MarkerTypes; element: google.maps.marker.AdvancedMarkerElement; property?: Building; + from: "Marker" | "List"; }; function createAdvancedMarker( @@ -48,6 +50,8 @@ export default function MapPage() { const [cautionMarkers, setCautionMarkers] = useState([]); const [isCautionAcitve, setIsCautionActive] = useState(true); + const { origin, setOrigin, destination, setDestination, switchBuilding } = useSearchRoute(); + const initMap = () => { if (map === null) return; map.addListener("click", (e: unknown) => { @@ -88,7 +92,12 @@ export default function MapPage() { center: { lat, lng }, zoom: 19, }); - setSelectedMarker({ type: "building", element: buildingMarker, property: building }); + setSelectedMarker({ + type: "building", + element: buildingMarker, + property: building, + from: "Marker", + }); }, ); } @@ -110,7 +119,11 @@ export default function MapPage() { hazardMarker.content = dangerFactors ? dangerMarkerContent(dangerFactors) : cautionMarkerContent(cautionFactors); - setSelectedMarker({ type: dangerFactors ? "danger" : "caution", element: hazardMarker }); + setSelectedMarker({ + type: dangerFactors ? "danger" : "caution", + element: hazardMarker, + from: "Marker", + }); }, ); if (dangerFactors) { @@ -146,6 +159,23 @@ export default function MapPage() { }); }; + const selectOriginNDestination = (type?: "origin" | "destination") => { + if (!selectedMarker || !selectedMarker.property || selectedMarker.type !== "building") return; + + if (selectedMarker.from === "Marker" && type) { + switch (type) { + case "origin": + setOrigin(selectedMarker.property); + break; + case "destination": + setDestination(selectedMarker.property); + break; + } + } + + setSheetOpen(false); + }; + useEffect(() => { initMap(); addBuildings(); @@ -169,9 +199,20 @@ export default function MapPage() { open={sheetOpen} snapPoints={({ minHeight }) => minHeight} > - {selectedMarker && ( - {}} buttonText="출발지 설정" building={selectedMarker} /> - )} + {selectedMarker && + (selectedMarker.from === "Marker" ? ( + selectOriginNDestination("origin")} + onClickRight={() => selectOriginNDestination("destination")} + /> + ) : ( + + ))}
); From 0324ed7ba43460a04e6cda18c6c4ee9e0a28678e Mon Sep 17 00:00:00 2001 From: dgfh0450 Date: Thu, 30 Jan 2025 18:47:18 +0900 Subject: [PATCH 09/16] =?UTF-8?q?[UNI-50]=20feat=20:=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?=20=EB=A7=88=EC=BB=A4=20=EC=83=89=EC=83=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assets/map/buildingMarker.svg} | 0 .../src/assets/map/selectedBuildingMarker.svg | 4 + .../src/components/map/mapMarkers.tsx | 95 +++++++++++-------- uniro_frontend/src/pages/map.tsx | 34 ++++++- 4 files changed, 90 insertions(+), 43 deletions(-) rename uniro_frontend/{public/map/building.svg => src/assets/map/buildingMarker.svg} (100%) create mode 100644 uniro_frontend/src/assets/map/selectedBuildingMarker.svg diff --git a/uniro_frontend/public/map/building.svg b/uniro_frontend/src/assets/map/buildingMarker.svg similarity index 100% rename from uniro_frontend/public/map/building.svg rename to uniro_frontend/src/assets/map/buildingMarker.svg diff --git a/uniro_frontend/src/assets/map/selectedBuildingMarker.svg b/uniro_frontend/src/assets/map/selectedBuildingMarker.svg new file mode 100644 index 0000000..1187dc7 --- /dev/null +++ b/uniro_frontend/src/assets/map/selectedBuildingMarker.svg @@ -0,0 +1,4 @@ + + + + diff --git a/uniro_frontend/src/components/map/mapMarkers.tsx b/uniro_frontend/src/components/map/mapMarkers.tsx index 33492b7..67cbaa7 100644 --- a/uniro_frontend/src/components/map/mapMarkers.tsx +++ b/uniro_frontend/src/components/map/mapMarkers.tsx @@ -1,58 +1,77 @@ export function buildingMarkerContent({ title }: { title: string }): HTMLElement { - const container = document.createElement("div"); - container.className = "translate-marker flex flex-col items-center space-y-[7px]"; + const container = document.createElement("div"); + container.className = "translate-marker flex flex-col items-center space-y-[7px]"; - const markerImage = document.createElement("img"); - markerImage.src = "/public/map/building.svg"; + const markerImage = document.createElement("img"); + markerImage.src = "/src/assets/map/buildingMarker.svg"; + markerImage.className = "text-system-red"; - const markerTitle = document.createElement("p"); - markerTitle.innerText = title; - markerTitle.className = "py-1 px-3 text-kor-caption font-medium text-gray-100 bg-gray-900 text-center rounded-200"; + const markerTitle = document.createElement("p"); + markerTitle.innerText = title; + markerTitle.className = "py-1 px-3 text-kor-caption font-medium text-gray-100 bg-gray-900 text-center rounded-200"; - container.appendChild(markerImage); - container.appendChild(markerTitle); + container.appendChild(markerImage); + container.appendChild(markerTitle); - return container; + return container; +} + +export function selectedBuildingMarkerContent({ title }: { title: string }): HTMLElement { + const container = document.createElement("div"); + container.className = "translate-marker flex flex-col items-center space-y-[7px]"; + + const markerImage = document.createElement("img"); + markerImage.src = "/src/assets/map/selectedBuildingMarker.svg"; + + const markerTitle = document.createElement("p"); + markerTitle.innerText = title; + markerTitle.className = + "py-1 px-3 text-kor-caption font-medium text-gray-100 bg-primary-500 text-center rounded-200"; + + container.appendChild(markerImage); + container.appendChild(markerTitle); + + return container; } export function cautionMarkerContent(factors?: string[]): HTMLElement { - const container = document.createElement("div"); - container.className = "translate-marker flex flex-col items-center space-y-[7px]"; + const container = document.createElement("div"); + container.className = "translate-marker flex flex-col items-center space-y-[7px]"; - if (factors) { - const markerFactor = document.createElement("p"); - markerFactor.innerText = factors[0]; - markerFactor.className = - "h-[38px] py-2 px-4 mb-2 text-kor-body3 font-semibold text-gray-100 bg-system-orange text-center rounded-200"; - container.classList.add("translate-y-[-46px]"); - container.appendChild(markerFactor); - } + if (factors) { + const markerFactor = document.createElement("p"); + markerFactor.innerText = factors[0]; + markerFactor.className = + "h-[38px] py-2 px-4 mb-2 text-kor-body3 font-semibold text-gray-100 bg-system-orange text-center rounded-200"; + container.classList.add("translate-y-[-46px]"); + container.appendChild(markerFactor); + } - const markerImage = document.createElement("img"); - markerImage.src = "/public/map/caution.svg"; + const markerImage = document.createElement("img"); + markerImage.src = "/public/map/caution.svg"; - container.appendChild(markerImage); + container.appendChild(markerImage); - return container; + return container; } export function dangerMarkerContent(factors?: string[]): HTMLElement { - const container = document.createElement("div"); - container.className = "translate-marker flex flex-col items-center space-y-[7px]"; + const container = document.createElement("div"); + container.className = "translate-marker flex flex-col items-center space-y-[7px]"; - if (factors) { - const markerFactor = document.createElement("p"); - markerFactor.innerText = factors[0]; - markerFactor.className = - "h-[38px] py-2 px-4 mb-2 text-kor-body3 font-semibold text-gray-100 bg-system-red text-center rounded-200"; - container.classList.add("translate-y-[-46px]"); - container.appendChild(markerFactor); - } + if (factors) { + const markerFactor = document.createElement("p"); + markerFactor.innerText = factors[0]; + markerFactor.className = + "h-[38px] py-2 px-4 mb-2 text-kor-body3 font-semibold text-gray-100 bg-system-red text-center rounded-200"; + container.classList.add("translate-y-[-46px]"); + container.appendChild(markerFactor); + } - const markerImage = document.createElement("img"); - markerImage.src = "/public/map/danger.svg"; + const markerImage = document.createElement("img"); + markerImage.src = "/public/map/danger.svg"; - container.appendChild(markerImage); + container.appendChild(markerImage); - return container; + return container; } diff --git a/uniro_frontend/src/pages/map.tsx b/uniro_frontend/src/pages/map.tsx index 000f7ec..fdf2801 100644 --- a/uniro_frontend/src/pages/map.tsx +++ b/uniro_frontend/src/pages/map.tsx @@ -1,7 +1,12 @@ import { useEffect, useRef, useState } from "react"; import useMap from "../hooks/useMap"; import { buildings } from "../data/mock/hanyangBuildings"; -import { buildingMarkerContent, cautionMarkerContent, dangerMarkerContent } from "../components/map/mapMarkers"; +import { + buildingMarkerContent, + cautionMarkerContent, + dangerMarkerContent, + selectedBuildingMarkerContent, +} from "../components/map/mapMarkers"; import { mockHazardEdges } from "../data/mock/hanyangHazardEdge"; import { BottomSheet, BottomSheetRef } from "react-spring-bottom-sheet"; import { Building } from "../data/types/node"; @@ -88,10 +93,6 @@ export default function MapPage() { buildingMarkerContent({ title: buildingName }), () => { setSheetOpen(true); - map?.setOptions({ - center: { lat, lng }, - zoom: 19, - }); setSelectedMarker({ type: "building", element: buildingMarker, @@ -176,12 +177,35 @@ export default function MapPage() { setSheetOpen(false); }; + const changeMarkerStyle = (isSelect: boolean) => { + if (!selectedMarker || selectedMarker.type !== "building" || !selectedMarker.property) return; + if (isSelect) { + selectedMarker.element.content = selectedBuildingMarkerContent({ + title: selectedMarker.property.buildingName, + }); + map?.setOptions({ + center: { lat: selectedMarker.property.lat, lng: selectedMarker.property.lng }, + zoom: 19, + }); + } else + selectedMarker.element.content = buildingMarkerContent({ + title: selectedMarker.property.buildingName, + }); + }; + useEffect(() => { initMap(); addBuildings(); addHazardMarker(); }, [map]); + useEffect(() => { + changeMarkerStyle(true); + return () => { + changeMarkerStyle(false); + }; + }, [selectedMarker]); + return (
From 7d418202824f38a78d881e47fe3ac25f63576b63 Mon Sep 17 00:00:00 2001 From: dgfh0450 Date: Thu, 30 Jan 2025 20:13:07 +0900 Subject: [PATCH 10/16] =?UTF-8?q?[UNI-51]=20feat=20:=20=EC=A7=80=EB=8F=84?= =?UTF-8?q?=20=EA=B2=80=EC=83=89=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=B0=8F?= =?UTF-8?q?=20=EC=A7=80=EB=8F=84=20=EB=A9=94=EC=9D=B8=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=97=B0=EA=B2=B0=20(global=20State=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- uniro_frontend/src/App.tsx | 2 + uniro_frontend/src/assets/call-thin.svg | 3 ++ uniro_frontend/src/assets/location-thin.svg | 3 ++ .../src/components/building/buildingList.tsx | 37 +++++++++++++++++ uniro_frontend/src/hooks/useSearchMode.ts | 18 ++++++++ uniro_frontend/src/pages/buildingSearch.tsx | 27 ++++++++++++ uniro_frontend/src/pages/map.tsx | 41 ++++++++++++++++--- 7 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 uniro_frontend/src/assets/call-thin.svg create mode 100644 uniro_frontend/src/assets/location-thin.svg create mode 100644 uniro_frontend/src/components/building/buildingList.tsx create mode 100644 uniro_frontend/src/hooks/useSearchMode.ts create mode 100644 uniro_frontend/src/pages/buildingSearch.tsx diff --git a/uniro_frontend/src/App.tsx b/uniro_frontend/src/App.tsx index b41b8d0..7f1413e 100644 --- a/uniro_frontend/src/App.tsx +++ b/uniro_frontend/src/App.tsx @@ -4,6 +4,7 @@ import Demo from "./pages/demo"; import LandingPage from "./pages/landing"; import UniversitySearchPage from "./pages/search"; import MapPage from "./pages/map"; +import BuildingSearchPage from "./pages/buildingSearch"; function App() { return ( @@ -11,6 +12,7 @@ function App() { } /> } /> } /> + } /> } /> ); diff --git a/uniro_frontend/src/assets/call-thin.svg b/uniro_frontend/src/assets/call-thin.svg new file mode 100644 index 0000000..43edfea --- /dev/null +++ b/uniro_frontend/src/assets/call-thin.svg @@ -0,0 +1,3 @@ + + + diff --git a/uniro_frontend/src/assets/location-thin.svg b/uniro_frontend/src/assets/location-thin.svg new file mode 100644 index 0000000..89fd9f7 --- /dev/null +++ b/uniro_frontend/src/assets/location-thin.svg @@ -0,0 +1,3 @@ + + + diff --git a/uniro_frontend/src/components/building/buildingList.tsx b/uniro_frontend/src/components/building/buildingList.tsx new file mode 100644 index 0000000..805274d --- /dev/null +++ b/uniro_frontend/src/components/building/buildingList.tsx @@ -0,0 +1,37 @@ +import { Building } from "../../data/types/node"; +import { Link } from "react-router"; +import CallIcon from "../../assets/call-thin.svg?react"; +import LocationIcon from "../../assets/location-thin.svg?react"; + +interface BuildingListProps { + building: Building; + onClick: () => void; +} + +export default function BuildingList({ building, onClick }: BuildingListProps) { + const { buildingName, buildingImageUrl, address, phoneNumber } = building; + return ( +
  • + +
    +

    {buildingName}

    +

    + + {address} +

    +

    + + {phoneNumber} +

    +
    +
    + +
    + +
  • + ); +} diff --git a/uniro_frontend/src/hooks/useSearchMode.ts b/uniro_frontend/src/hooks/useSearchMode.ts new file mode 100644 index 0000000..7ab088b --- /dev/null +++ b/uniro_frontend/src/hooks/useSearchMode.ts @@ -0,0 +1,18 @@ +import { create } from "zustand"; +import { Building } from "../data/types/node"; + +interface SearchModeStore { + mode: "origin" | "destination"; + setMode: (mode: "origin" | "destination") => void; + building: Building | undefined; + setBuilding: (newBuilding: Building) => void; +} + +const useSearchMode = create((set) => ({ + mode: "origin", + setMode: (newMode: "origin" | "destination") => set(() => ({ mode: newMode })), + building: undefined, + setBuilding: (newBuilding: Building) => set(() => ({ building: newBuilding })), +})); + +export default useSearchMode; diff --git a/uniro_frontend/src/pages/buildingSearch.tsx b/uniro_frontend/src/pages/buildingSearch.tsx new file mode 100644 index 0000000..16a29a1 --- /dev/null +++ b/uniro_frontend/src/pages/buildingSearch.tsx @@ -0,0 +1,27 @@ +import React from "react"; +import Input from "../components/customInput"; +import { buildings } from "../data/mock/hanyangBuildings"; +import BuildingList from "../components/building/buildingList"; +import useSearchMode from "../hooks/useSearchMode"; + +export default function BuildingSearchPage() { + const { setBuilding } = useSearchMode(); + return ( +
    +
    + {}} handleVoiceInput={() => {}} placeholder="" /> +
    +
    +
      + {buildings.map((building) => ( + setBuilding(building)} + key={`building-${building.buildingName}`} + building={building} + /> + ))} +
    +
    +
    + ); +} diff --git a/uniro_frontend/src/pages/map.tsx b/uniro_frontend/src/pages/map.tsx index fdf2801..d8b1b69 100644 --- a/uniro_frontend/src/pages/map.tsx +++ b/uniro_frontend/src/pages/map.tsx @@ -16,6 +16,7 @@ import TopSheet from "../components/map/TopSheet"; import { CautionToggleButton, DangerToggleButton } from "../components/map/floatingButtons"; import ReportButton from "../components/map/reportButton"; import useSearchRoute from "../hooks/useSearchRoute"; +import useSearchMode from "../hooks/useSearchMode"; type MarkerTypes = "building" | "caution" | "danger"; export type SelectedMarkerTypes = { @@ -49,6 +50,12 @@ export default function MapPage() { const bottomSheetRef = useRef(null); const [sheetOpen, setSheetOpen] = useState(false); + const [buildingMarkers, setBuildingMarkers] = useState< + { + element: google.maps.marker.AdvancedMarkerElement; + id: string; + }[] + >([]); const [dangerMarkers, setDangerMarkers] = useState([]); const [isDangerAcitve, setIsDangerActive] = useState(true); @@ -56,10 +63,12 @@ export default function MapPage() { const [isCautionAcitve, setIsCautionActive] = useState(true); const { origin, setOrigin, destination, setDestination, switchBuilding } = useSearchRoute(); + const { mode, setMode, building, setBuilding } = useSearchMode(); const initMap = () => { if (map === null) return; map.addListener("click", (e: unknown) => { + setSheetOpen(false); setSelectedMarker((marker) => { if (marker) { const { type, element } = marker; @@ -71,9 +80,6 @@ export default function MapPage() { case "danger": element.content = dangerMarkerContent(); break; - case "building": - setSheetOpen(false); - break; } } return undefined; @@ -83,6 +89,8 @@ export default function MapPage() { const addBuildings = () => { if (AdvancedMarker === null || map === null) return; + + const markersWithId: { id: string; element: google.maps.marker.AdvancedMarkerElement }[] = []; for (const building of buildings) { const { id, lat, lng, buildingName } = building; @@ -92,7 +100,6 @@ export default function MapPage() { new google.maps.LatLng(lat, lng), buildingMarkerContent({ title: buildingName }), () => { - setSheetOpen(true); setSelectedMarker({ type: "building", element: buildingMarker, @@ -101,7 +108,11 @@ export default function MapPage() { }); }, ); + + markersWithId.push({ id: id ? id : "", element: buildingMarker }); } + + setBuildingMarkers(markersWithId); }; const addHazardMarker = () => { @@ -172,6 +183,9 @@ export default function MapPage() { setDestination(selectedMarker.property); break; } + } else { + if (!origin) setOrigin(selectedMarker.property); + else setDestination(selectedMarker.property); } setSheetOpen(false); @@ -179,6 +193,7 @@ export default function MapPage() { const changeMarkerStyle = (isSelect: boolean) => { if (!selectedMarker || selectedMarker.type !== "building" || !selectedMarker.property) return; + if (isSelect) { selectedMarker.element.content = selectedBuildingMarkerContent({ title: selectedMarker.property.buildingName, @@ -187,6 +202,7 @@ export default function MapPage() { center: { lat: selectedMarker.property.lat, lng: selectedMarker.property.lng }, zoom: 19, }); + setSheetOpen(true); } else selectedMarker.element.content = buildingMarkerContent({ title: selectedMarker.property.buildingName, @@ -200,12 +216,27 @@ export default function MapPage() { }, [map]); useEffect(() => { + if (selectedMarker === undefined) return; changeMarkerStyle(true); return () => { changeMarkerStyle(false); }; }, [selectedMarker]); + useEffect(() => { + if (buildingMarkers.length === 0 || !building) return; + + const matchedMarker = buildingMarkers.find((el) => el.id === building.id)?.element; + + if (matchedMarker) + setSelectedMarker({ + type: "building", + element: matchedMarker, + from: "List", + property: building, + }); + }, [building, buildingMarkers]); + return (
    @@ -233,7 +264,7 @@ export default function MapPage() { ) : ( ))} From 7c043d532cd25dd5aae3b2271ca5931e4f17d5e5 Mon Sep 17 00:00:00 2001 From: dgfh0450 Date: Thu, 30 Jan 2025 20:23:37 +0900 Subject: [PATCH 11/16] =?UTF-8?q?[UNI-50]=20feat=20:=20=EC=A7=80=EB=8F=84?= =?UTF-8?q?=20=EB=A9=94=EC=9D=B8=ED=8E=98=EC=9D=B4=EC=A7=80=20Input,=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- uniro_frontend/src/components/map/TopSheet.tsx | 8 ++++++++ .../src/components/map/routeSearchInput.tsx | 17 ++++++++++------- uniro_frontend/src/pages/map.tsx | 11 ++++++----- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/uniro_frontend/src/components/map/TopSheet.tsx b/uniro_frontend/src/components/map/TopSheet.tsx index 1ece4e8..4a7538a 100644 --- a/uniro_frontend/src/components/map/TopSheet.tsx +++ b/uniro_frontend/src/components/map/TopSheet.tsx @@ -7,9 +7,11 @@ import { Link } from "react-router"; import { motion } from "framer-motion"; import useSearchRoute from "../../hooks/useSearchRoute"; import { useEffect } from "react"; +import useSearchMode from "../../hooks/useSearchMode"; export default function TopSheet({ open }: { open: boolean }) { const { origin, setOrigin, destination, setDestination, switchBuilding } = useSearchRoute(); + const { setMode } = useSearchMode(); return (
    { + setMode("origin"); + }} placeholder="출발지를 입력하세요" value={origin ? origin.buildingName : ""} onCancel={() => setOrigin(undefined)} @@ -33,6 +38,9 @@ export default function TopSheet({ open }: { open: boolean }) { { + setMode("destination"); + }} placeholder="도착지를 입력하세요" value={destination ? destination.buildingName : ""} onCancel={() => setDestination(undefined)} diff --git a/uniro_frontend/src/components/map/routeSearchInput.tsx b/uniro_frontend/src/components/map/routeSearchInput.tsx index 9ddde1c..152787f 100644 --- a/uniro_frontend/src/components/map/routeSearchInput.tsx +++ b/uniro_frontend/src/components/map/routeSearchInput.tsx @@ -1,25 +1,28 @@ import { InputHTMLAttributes, ReactNode } from "react"; import Close from "/public/icons/close-circle.svg?react"; +import { Link } from "react-router"; interface RouteInputProps extends InputHTMLAttributes { placeholder: string; children: ReactNode; value?: string; onCancel?: () => void; + onClick: () => void; } -export default function RouteInput({ placeholder, children, value, onCancel }: RouteInputProps) { +export default function RouteInput({ placeholder, children, value, onCancel, onClick }: RouteInputProps) { return (
    {children} - + + {value ? value : placeholder} + {value && ( +
    + ) : ( + <> +
    + +
    +
    + + +
    + + )}
    ); } From 03b82a850ecceeeeb6d4f4db13c49f64ff8e2b31 Mon Sep 17 00:00:00 2001 From: dgfh0450 Date: Thu, 30 Jan 2025 23:21:50 +0900 Subject: [PATCH 13/16] =?UTF-8?q?[UNI-49]=20refactor=20:=20=ED=95=98?= =?UTF-8?q?=EB=93=9C=EC=BD=94=EB=94=A9=20=EB=B3=80=EC=88=98=20ENUM=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20rename?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/map/TopSheet.tsx | 18 ++-- uniro_frontend/src/constant/enums.ts | 10 ++ uniro_frontend/src/data/types/marker.d.ts | 5 + uniro_frontend/src/data/types/route.d.ts | 3 + .../{useSearchRoute.ts => useRoutePoint.ts} | 5 +- uniro_frontend/src/hooks/useSearchBuilding.ts | 21 +++++ uniro_frontend/src/hooks/useSearchMode.ts | 18 ---- uniro_frontend/src/pages/buildingSearch.tsx | 5 +- uniro_frontend/src/pages/map.tsx | 92 +++++++++++-------- 9 files changed, 103 insertions(+), 74 deletions(-) create mode 100644 uniro_frontend/src/constant/enums.ts create mode 100644 uniro_frontend/src/data/types/marker.d.ts rename uniro_frontend/src/hooks/{useSearchRoute.ts => useRoutePoint.ts} (83%) create mode 100644 uniro_frontend/src/hooks/useSearchBuilding.ts delete mode 100644 uniro_frontend/src/hooks/useSearchMode.ts diff --git a/uniro_frontend/src/components/map/TopSheet.tsx b/uniro_frontend/src/components/map/TopSheet.tsx index 4a7538a..3d478d1 100644 --- a/uniro_frontend/src/components/map/TopSheet.tsx +++ b/uniro_frontend/src/components/map/TopSheet.tsx @@ -5,13 +5,13 @@ import LocationIcon from "../../../public/icons/location-thick.svg?react"; import SwitchIcon from "../../assets/switch.svg?react"; import { Link } from "react-router"; import { motion } from "framer-motion"; -import useSearchRoute from "../../hooks/useSearchRoute"; -import { useEffect } from "react"; -import useSearchMode from "../../hooks/useSearchMode"; +import useRoutePoint from "../../hooks/useRoutePoint"; +import useSearchBuilding from "../../hooks/useSearchBuilding"; +import { RoutePoint } from "../../constant/enums"; export default function TopSheet({ open }: { open: boolean }) { - const { origin, setOrigin, destination, setDestination, switchBuilding } = useSearchRoute(); - const { setMode } = useSearchMode(); + const { origin, setOrigin, destination, setDestination, switchBuilding } = useRoutePoint(); + const { setMode } = useSearchBuilding(); return (
    { - setMode("origin"); - }} + onClick={() => setMode(RoutePoint.ORIGIN)} placeholder="출발지를 입력하세요" value={origin ? origin.buildingName : ""} onCancel={() => setOrigin(undefined)} @@ -38,9 +36,7 @@ export default function TopSheet({ open }: { open: boolean }) { { - setMode("destination"); - }} + onClick={() => setMode(RoutePoint.DESTINATION)} placeholder="도착지를 입력하세요" value={destination ? destination.buildingName : ""} onCancel={() => setDestination(undefined)} diff --git a/uniro_frontend/src/constant/enums.ts b/uniro_frontend/src/constant/enums.ts new file mode 100644 index 0000000..4530637 --- /dev/null +++ b/uniro_frontend/src/constant/enums.ts @@ -0,0 +1,10 @@ +export const enum Markers { + CAUTION = "origin", + DANGER = "danger", + BUILDING = "building", +} + +export const enum RoutePoint { + ORIGIN = "origin", + DESTINATION = "destination", +} diff --git a/uniro_frontend/src/data/types/marker.d.ts b/uniro_frontend/src/data/types/marker.d.ts new file mode 100644 index 0000000..08d5c31 --- /dev/null +++ b/uniro_frontend/src/data/types/marker.d.ts @@ -0,0 +1,5 @@ +import { Markers } from "../../constant/enums"; + +export type AdvancedMarker = google.maps.marker.AdvancedMarkerElement; + +export type MarkerTypes = Markers.BUILDING | Markers.CAUTION | Markers.DANGER; diff --git a/uniro_frontend/src/data/types/route.d.ts b/uniro_frontend/src/data/types/route.d.ts index a335dc5..656923d 100644 --- a/uniro_frontend/src/data/types/route.d.ts +++ b/uniro_frontend/src/data/types/route.d.ts @@ -1,3 +1,4 @@ +import { RoutePoint } from "../../constant/enums"; import { HazardEdge } from "./edge"; export interface Route { @@ -9,3 +10,5 @@ export interface NavigationRoute extends Route { totalDistance: number; totalCost: number; } + +export type RoutePointType = RoutePoint.ORIGIN | RoutePoint.DESTINATION; diff --git a/uniro_frontend/src/hooks/useSearchRoute.ts b/uniro_frontend/src/hooks/useRoutePoint.ts similarity index 83% rename from uniro_frontend/src/hooks/useSearchRoute.ts rename to uniro_frontend/src/hooks/useRoutePoint.ts index 660ea29..50b6d88 100644 --- a/uniro_frontend/src/hooks/useSearchRoute.ts +++ b/uniro_frontend/src/hooks/useRoutePoint.ts @@ -9,7 +9,8 @@ interface RouteStore { switchBuilding: () => void; } -const useSearchRoute = create((set) => ({ +/** 출발지, 도착지 관리 전역 상태 */ +const useRoutePoint = create((set) => ({ origin: undefined, setOrigin: (newOrigin: Building | undefined) => set(() => ({ origin: newOrigin })), destination: undefined, @@ -17,4 +18,4 @@ const useSearchRoute = create((set) => ({ switchBuilding: () => set(({ origin, destination }) => ({ origin: destination, destination: origin })), })); -export default useSearchRoute; +export default useRoutePoint; diff --git a/uniro_frontend/src/hooks/useSearchBuilding.ts b/uniro_frontend/src/hooks/useSearchBuilding.ts new file mode 100644 index 0000000..b397f85 --- /dev/null +++ b/uniro_frontend/src/hooks/useSearchBuilding.ts @@ -0,0 +1,21 @@ +import { create } from "zustand"; +import { Building } from "../data/types/node"; +import { RoutePointType } from "../data/types/route"; +import { RoutePoint } from "../constant/enums"; + +interface SearchModeStore { + mode: RoutePointType; + setMode: (mode: RoutePointType) => void; + building: Building | undefined; + setBuilding: (newBuilding: Building) => void; +} + +/** 건물 리스트에서 건물을 출발지, 도착지로 결정하는 경우 */ +const useSearchBuilding = create((set) => ({ + mode: RoutePoint.ORIGIN, + setMode: (newMode: RoutePointType) => set(() => ({ mode: newMode })), + building: undefined, + setBuilding: (newBuilding: Building) => set(() => ({ building: newBuilding })), +})); + +export default useSearchBuilding; diff --git a/uniro_frontend/src/hooks/useSearchMode.ts b/uniro_frontend/src/hooks/useSearchMode.ts deleted file mode 100644 index 7ab088b..0000000 --- a/uniro_frontend/src/hooks/useSearchMode.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { create } from "zustand"; -import { Building } from "../data/types/node"; - -interface SearchModeStore { - mode: "origin" | "destination"; - setMode: (mode: "origin" | "destination") => void; - building: Building | undefined; - setBuilding: (newBuilding: Building) => void; -} - -const useSearchMode = create((set) => ({ - mode: "origin", - setMode: (newMode: "origin" | "destination") => set(() => ({ mode: newMode })), - building: undefined, - setBuilding: (newBuilding: Building) => set(() => ({ building: newBuilding })), -})); - -export default useSearchMode; diff --git a/uniro_frontend/src/pages/buildingSearch.tsx b/uniro_frontend/src/pages/buildingSearch.tsx index 16a29a1..aa297b4 100644 --- a/uniro_frontend/src/pages/buildingSearch.tsx +++ b/uniro_frontend/src/pages/buildingSearch.tsx @@ -1,11 +1,10 @@ -import React from "react"; import Input from "../components/customInput"; import { buildings } from "../data/mock/hanyangBuildings"; import BuildingList from "../components/building/buildingList"; -import useSearchMode from "../hooks/useSearchMode"; +import useSearchBuilding from "../hooks/useSearchBuilding"; export default function BuildingSearchPage() { - const { setBuilding } = useSearchMode(); + const { setBuilding } = useSearchBuilding(); return (
    diff --git a/uniro_frontend/src/pages/map.tsx b/uniro_frontend/src/pages/map.tsx index 91cafa7..bd58a24 100644 --- a/uniro_frontend/src/pages/map.tsx +++ b/uniro_frontend/src/pages/map.tsx @@ -17,14 +17,17 @@ import { MapBottomSheetFromList, MapBottomSheetFromMarker } from "../components/ import TopSheet from "../components/map/TopSheet"; import { CautionToggleButton, DangerToggleButton } from "../components/map/floatingButtons"; import ReportButton from "../components/map/reportButton"; -import useSearchRoute from "../hooks/useSearchRoute"; -import useSearchMode from "../hooks/useSearchMode"; +import useRoutePoint from "../hooks/useRoutePoint"; +import useSearchBuilding from "../hooks/useSearchBuilding"; import Button from "../components/customButton"; +import { AdvancedMarker, MarkerTypes } from "../data/types/marker"; +import { RoutePointType } from "../data/types/route"; +import { RoutePoint } from "../constant/enums"; +import { Markers } from "../constant/enums"; -type MarkerTypes = "building" | "caution" | "danger"; export type SelectedMarkerTypes = { type: MarkerTypes; - element: google.maps.marker.AdvancedMarkerElement; + element: AdvancedMarker; property?: Building; from: "Marker" | "List"; }; @@ -34,7 +37,7 @@ function createAdvancedMarker( map: google.maps.Map, position: google.maps.LatLng, content: HTMLElement, - clickCallback: () => void, + onClick: () => void, ) { const newMarker = new AdvancedMarker({ map: map, @@ -42,7 +45,7 @@ function createAdvancedMarker( content: content, }); - newMarker.addListener("click", clickCallback); + newMarker.addListener("click", onClick); return newMarker; } @@ -53,20 +56,15 @@ export default function MapPage() { const bottomSheetRef = useRef(null); const [sheetOpen, setSheetOpen] = useState(false); - const [buildingMarkers, setBuildingMarkers] = useState< - { - element: google.maps.marker.AdvancedMarkerElement; - id: string; - }[] - >([]); - const [dangerMarkers, setDangerMarkers] = useState([]); + const [buildingMarkers, setBuildingMarkers] = useState<{ element: AdvancedMarker; id: string }[]>([]); + const [dangerMarkers, setDangerMarkers] = useState([]); const [isDangerAcitve, setIsDangerActive] = useState(true); - const [cautionMarkers, setCautionMarkers] = useState([]); + const [cautionMarkers, setCautionMarkers] = useState([]); const [isCautionAcitve, setIsCautionActive] = useState(true); - const { origin, setOrigin, destination, setDestination, switchBuilding } = useSearchRoute(); - const { mode, setMode, building, setBuilding } = useSearchMode(); + const { origin, setOrigin, destination, setDestination } = useRoutePoint(); + const { mode, building: selectedBuilding } = useSearchBuilding(); const initMap = () => { if (map === null) return; @@ -77,10 +75,10 @@ export default function MapPage() { const { type, element } = marker; switch (type) { - case "caution": + case Markers.CAUTION: element.content = cautionMarkerContent(); break; - case "danger": + case Markers.DANGER: element.content = dangerMarkerContent(); break; } @@ -93,7 +91,7 @@ export default function MapPage() { const addBuildings = () => { if (AdvancedMarker === null || map === null) return; - const markersWithId: { id: string; element: google.maps.marker.AdvancedMarkerElement }[] = []; + const markersWithId: { id: string; element: AdvancedMarker }[] = []; for (const building of buildings) { const { id, lat, lng, buildingName } = building; @@ -104,7 +102,7 @@ export default function MapPage() { buildingMarkerContent({ title: buildingName }), () => { setSelectedMarker({ - type: "building", + type: Markers.BUILDING, element: buildingMarker, property: building, from: "Marker", @@ -135,7 +133,7 @@ export default function MapPage() { ? dangerMarkerContent(dangerFactors) : cautionMarkerContent(cautionFactors); setSelectedMarker({ - type: dangerFactors ? "danger" : "caution", + type: dangerFactors ? Markers.DANGER : Markers.CAUTION, element: hazardMarker, from: "Marker", }); @@ -149,7 +147,8 @@ export default function MapPage() { } }; - const toggleMarkers = (isActive: boolean, markers: google.maps.marker.AdvancedMarkerElement[]) => { + /** Marker 보이기 안보이기 토글 */ + const toggleMarkers = (isActive: boolean, markers: AdvancedMarker[]) => { if (isActive) { for (const marker of markers) { marker.map = map; @@ -174,15 +173,16 @@ export default function MapPage() { }); }; - const selectOriginNDestination = (type?: "origin" | "destination") => { - if (!selectedMarker || !selectedMarker.property || selectedMarker.type !== "building") return; + /** 선택된 마커의 출처 (Marker, List), Type을 비교하여 출발지, 도착지 지정 */ + const selectRoutePoint = (type?: RoutePointType) => { + if (!selectedMarker || !selectedMarker.property || selectedMarker.type !== Markers.BUILDING) return; if (selectedMarker.from === "Marker" && type) { switch (type) { - case "origin": + case RoutePoint.ORIGIN: setOrigin(selectedMarker.property); break; - case "destination": + case RoutePoint.DESTINATION: setDestination(selectedMarker.property); break; } @@ -195,14 +195,15 @@ export default function MapPage() { setSelectedMarker(undefined); }; - const changeMarkerStyle = (marker: google.maps.marker.AdvancedMarkerElement, isSelect: boolean) => { - if (!selectedMarker || selectedMarker.type !== "building" || !selectedMarker.property) return; + /** isSelect(Marker 선택 시) Marker Content 변경, 지도 이동, BottomSheet 열기 */ + const changeMarkerStyle = (marker: AdvancedMarker, isSelect: boolean) => { + if (!map || !selectedMarker || selectedMarker.type !== Markers.BUILDING || !selectedMarker.property) return; if (isSelect) { marker.content = selectedBuildingMarkerContent({ title: selectedMarker.property.buildingName, }); - map?.setOptions({ + map.setOptions({ center: { lat: selectedMarker.property.lat, lng: selectedMarker.property.lng }, zoom: 19, }); @@ -213,18 +214,20 @@ export default function MapPage() { }); }; - const findBuildingMarker = (id: string): google.maps.marker.AdvancedMarkerElement | undefined => { + const findBuildingMarker = (id: string): AdvancedMarker | undefined => { const matchedMarker = buildingMarkers.find((el) => el.id === id)?.element; return matchedMarker; }; + /** 초기 렌더링 시, 건물 | 위험 | 주의 마커 생성 */ useEffect(() => { initMap(); addBuildings(); addHazardMarker(); }, [map]); + /** 선택된 마커가 있는 경우 */ useEffect(() => { if (selectedMarker === undefined) return; changeMarkerStyle(selectedMarker.element, true); @@ -233,22 +236,25 @@ export default function MapPage() { }; }, [selectedMarker]); + /** 빌딩 리스트에서 넘어온 경우, 일치하는 BuildingMarkerElement를 탐색 */ useEffect(() => { - if (buildingMarkers.length === 0 || !building || !building.id) return; + if (buildingMarkers.length === 0 || !selectedBuilding || !selectedBuilding.id) return; - const matchedMarker = findBuildingMarker(building.id); + const matchedMarker = findBuildingMarker(selectedBuilding.id); if (matchedMarker) setSelectedMarker({ - type: "building", + type: Markers.BUILDING, element: matchedMarker, from: "List", - property: building, + property: selectedBuilding, }); - }, [building, buildingMarkers]); + }, [selectedBuilding, buildingMarkers]); + /** 출발지 결정 시, Marker Content 변경 */ useEffect(() => { if (!origin || !origin.id) return; + const originMarker = findBuildingMarker(origin.id); if (!originMarker) return; @@ -259,8 +265,10 @@ export default function MapPage() { }; }, [origin]); + /** 도착지 결정 시, Marker Content 변경 */ useEffect(() => { if (!destination || !destination.id) return; + const destinationMarker = findBuildingMarker(destination.id); if (!destinationMarker) return; @@ -270,11 +278,11 @@ export default function MapPage() { destinationMarker.content = buildingMarkerContent({ title: destination.buildingName }); }; }, [destination]); + return (
    - {selectedMarker && (selectedMarker.from === "Marker" ? ( + /** 선택된 마커가 Marker 클릭에서 온 경우 */ selectOriginNDestination("origin")} - onClickRight={() => selectOriginNDestination("destination")} + onClickLeft={() => selectRoutePoint(RoutePoint.ORIGIN)} + onClickRight={() => selectRoutePoint(RoutePoint.DESTINATION)} /> ) : ( + /** 선택된 마커가 리스트에서 온 경우 */ ))} {origin && destination && origin.id !== destination.id ? ( + /** 출발지랑 도착지가 존재하는 경우 길찾기 버튼 보이기 */
    ) : ( + /** 출발지랑 도착지가 존재하지 않거나, 같은 경우 기존 Button UI 보이기 */ <>
    From 2ea6b2508d43085ad0b2d32b4f515c309157e0db Mon Sep 17 00:00:00 2001 From: dgfh0450 Date: Fri, 31 Jan 2025 16:29:25 +0900 Subject: [PATCH 14/16] =?UTF-8?q?[UNI-49]=20refactor=20:=20createMarkerEle?= =?UTF-8?q?ment=20=ED=95=A8=EC=88=98=20=EB=B3=91=ED=95=A9=20=EB=B0=8F=20EN?= =?UTF-8?q?UM=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../building.svg} | 0 .../map => src/assets/markers}/caution.svg | 0 .../map => src/assets/markers}/danger.svg | 0 .../destination.svg} | 0 .../originMarker.svg => markers/origin.svg} | 0 .../selectedBuilding.svg} | 0 .../src/components/map/mapMarkers.tsx | 156 +- uniro_frontend/src/constant/enums.ts | 7 +- uniro_frontend/src/data/mock/hanyangPath.json | 5440 ++++++++--------- uniro_frontend/src/data/types/marker.d.ts | 10 +- uniro_frontend/src/pages/demo.tsx | 11 +- uniro_frontend/src/pages/map.tsx | 88 +- uniro_frontend/src/pages/search.tsx | 2 +- .../src/utils/markers/createAdvanedMarker.ts | 17 + 14 files changed, 2862 insertions(+), 2869 deletions(-) rename uniro_frontend/src/assets/{map/buildingMarker.svg => markers/building.svg} (100%) rename uniro_frontend/{public/map => src/assets/markers}/caution.svg (100%) rename uniro_frontend/{public/map => src/assets/markers}/danger.svg (100%) rename uniro_frontend/src/assets/{map/destinationMarker.svg => markers/destination.svg} (100%) rename uniro_frontend/src/assets/{map/originMarker.svg => markers/origin.svg} (100%) rename uniro_frontend/src/assets/{map/selectedBuildingMarker.svg => markers/selectedBuilding.svg} (100%) create mode 100644 uniro_frontend/src/utils/markers/createAdvanedMarker.ts diff --git a/uniro_frontend/src/assets/map/buildingMarker.svg b/uniro_frontend/src/assets/markers/building.svg similarity index 100% rename from uniro_frontend/src/assets/map/buildingMarker.svg rename to uniro_frontend/src/assets/markers/building.svg diff --git a/uniro_frontend/public/map/caution.svg b/uniro_frontend/src/assets/markers/caution.svg similarity index 100% rename from uniro_frontend/public/map/caution.svg rename to uniro_frontend/src/assets/markers/caution.svg diff --git a/uniro_frontend/public/map/danger.svg b/uniro_frontend/src/assets/markers/danger.svg similarity index 100% rename from uniro_frontend/public/map/danger.svg rename to uniro_frontend/src/assets/markers/danger.svg diff --git a/uniro_frontend/src/assets/map/destinationMarker.svg b/uniro_frontend/src/assets/markers/destination.svg similarity index 100% rename from uniro_frontend/src/assets/map/destinationMarker.svg rename to uniro_frontend/src/assets/markers/destination.svg diff --git a/uniro_frontend/src/assets/map/originMarker.svg b/uniro_frontend/src/assets/markers/origin.svg similarity index 100% rename from uniro_frontend/src/assets/map/originMarker.svg rename to uniro_frontend/src/assets/markers/origin.svg diff --git a/uniro_frontend/src/assets/map/selectedBuildingMarker.svg b/uniro_frontend/src/assets/markers/selectedBuilding.svg similarity index 100% rename from uniro_frontend/src/assets/map/selectedBuildingMarker.svg rename to uniro_frontend/src/assets/markers/selectedBuilding.svg diff --git a/uniro_frontend/src/components/map/mapMarkers.tsx b/uniro_frontend/src/components/map/mapMarkers.tsx index 36adb62..9e4eaf9 100644 --- a/uniro_frontend/src/components/map/mapMarkers.tsx +++ b/uniro_frontend/src/components/map/mapMarkers.tsx @@ -1,113 +1,83 @@ -export function buildingMarkerContent({ title }: { title: string }): HTMLElement { - const container = document.createElement("div"); - container.className = "translate-marker flex flex-col items-center space-y-[7px]"; - - const markerImage = document.createElement("img"); - markerImage.src = "/src/assets/map/buildingMarker.svg"; - markerImage.className = "text-system-red"; +import { MarkerTypes } from "../../data/types/marker"; +import { Markers } from "../../constant/enums"; +function createTextElement(type: MarkerTypes, title: string): HTMLElement { const markerTitle = document.createElement("p"); markerTitle.innerText = title; - markerTitle.className = "py-1 px-3 text-kor-caption font-medium text-gray-100 bg-gray-900 text-center rounded-200"; - container.appendChild(markerImage); - container.appendChild(markerTitle); - - return container; -} - -export function selectedBuildingMarkerContent({ title }: { title: string }): HTMLElement { - const container = document.createElement("div"); - container.className = "translate-marker flex flex-col items-center space-y-[7px]"; - - const markerImage = document.createElement("img"); - markerImage.src = "/src/assets/map/selectedBuildingMarker.svg"; - - const markerTitle = document.createElement("p"); - markerTitle.innerText = title; - markerTitle.className = - "py-1 px-3 text-kor-caption font-medium text-gray-100 bg-primary-500 text-center rounded-200"; - - container.appendChild(markerImage); - container.appendChild(markerTitle); - - return container; -} - -export function cautionMarkerContent(factors?: string[]): HTMLElement { - const container = document.createElement("div"); - container.className = "translate-marker flex flex-col items-center space-y-[7px]"; - - if (factors) { - const markerFactor = document.createElement("p"); - markerFactor.innerText = factors[0]; - markerFactor.className = - "h-[38px] py-2 px-4 mb-2 text-kor-body3 font-semibold text-gray-100 bg-system-orange text-center rounded-200"; - container.classList.add("translate-y-[-46px]"); - container.appendChild(markerFactor); + switch (type) { + case Markers.CAUTION: + markerTitle.className = + "h-[38px] py-2 px-4 mb-2 text-kor-body3 font-semibold text-gray-100 bg-system-orange text-center rounded-200"; + return markerTitle; + case Markers.DANGER: + markerTitle.className = + "h-[38px] py-2 px-4 mb-2 text-kor-body3 font-semibold text-gray-100 bg-system-red text-center rounded-200"; + return markerTitle; + case Markers.BUILDING: + markerTitle.className = + "py-1 px-3 text-kor-caption font-medium text-gray-100 bg-gray-900 text-center rounded-200"; + return markerTitle; + case Markers.SELECTED_BUILDING: + markerTitle.className = + "py-1 px-3 text-kor-caption font-medium text-gray-100 bg-primary-500 text-center rounded-200"; + return markerTitle; + case Markers.ORIGIN: + markerTitle.className = + "py-1 px-3 text-kor-caption font-medium text-gray-100 bg-primary-500 text-center rounded-200"; + return markerTitle; + case Markers.DESTINATION: + markerTitle.className = + "py-1 px-3 text-kor-caption font-medium text-gray-100 bg-primary-500 text-center rounded-200"; + return markerTitle; + default: + return markerTitle; } - - const markerImage = document.createElement("img"); - markerImage.src = "/public/map/caution.svg"; - - container.appendChild(markerImage); - - return container; } -export function dangerMarkerContent(factors?: string[]): HTMLElement { - const container = document.createElement("div"); - container.className = "translate-marker flex flex-col items-center space-y-[7px]"; - - if (factors) { - const markerFactor = document.createElement("p"); - markerFactor.innerText = factors[0]; - markerFactor.className = - "h-[38px] py-2 px-4 mb-2 text-kor-body3 font-semibold text-gray-100 bg-system-red text-center rounded-200"; - container.classList.add("translate-y-[-46px]"); - container.appendChild(markerFactor); - } - +function createImageElement(type: MarkerTypes): HTMLElement { const markerImage = document.createElement("img"); - markerImage.src = "/public/map/danger.svg"; - container.appendChild(markerImage); - - return container; + markerImage.src = `/src/assets/markers/${type}.svg`; + return markerImage; } -export function originMarkerContent({ title }: { title: string }): HTMLElement { +function createContainerElement(className?: string) { const container = document.createElement("div"); - container.className = "translate-routemarker flex flex-col items-center space-y-[7px]"; - - const markerImage = document.createElement("img"); - markerImage.src = "/src/assets/map/originMarker.svg"; - - const markerTitle = document.createElement("p"); - markerTitle.innerText = title; - markerTitle.className = - "py-1 px-3 text-kor-caption font-medium text-gray-100 bg-primary-500 text-center rounded-200"; - - container.appendChild(markerImage); - container.appendChild(markerTitle); + console.log(className); + container.className = `flex flex-col items-center space-y-[7px] ${className}`; return container; } -export function destinationMarkerContent({ title }: { title: string }): HTMLElement { - const container = document.createElement("div"); - container.className = "translate-routemarker flex flex-col items-center space-y-[7px]"; - - const markerImage = document.createElement("img"); - markerImage.src = "/src/assets/map/destinationMarker.svg"; - - const markerTitle = document.createElement("p"); - markerTitle.innerText = title; - markerTitle.className = - "py-1 px-3 text-kor-caption font-medium text-gray-100 bg-primary-500 text-center rounded-200"; +export default function createMarkerElement({ + type, + title, + className, + hasTopContent = false, +}: { + type: MarkerTypes; + className?: string; + title?: string; + hasTopContent?: boolean; +}): HTMLElement { + const container = createContainerElement(className); + + const markerImage = createImageElement(type); + + if (title) { + const markerTitle = createTextElement(type, title); + if (hasTopContent) { + container.appendChild(markerTitle); + container.appendChild(markerImage); + return container; + } + + container.appendChild(markerImage); + container.appendChild(markerTitle); + return container; + } container.appendChild(markerImage); - container.appendChild(markerTitle); - return container; } diff --git a/uniro_frontend/src/constant/enums.ts b/uniro_frontend/src/constant/enums.ts index 4530637..e816ddb 100644 --- a/uniro_frontend/src/constant/enums.ts +++ b/uniro_frontend/src/constant/enums.ts @@ -1,7 +1,12 @@ export const enum Markers { - CAUTION = "origin", + CAUTION = "caution", DANGER = "danger", BUILDING = "building", + ORIGIN = "origin", + DESTINATION = "destination", + SELECTED_BUILDING = "selectedBuilding", + WAYPOINT = "waypoint", + NUMBERED_WAYPOINT = "numberedWayPoint", } export const enum RoutePoint { diff --git a/uniro_frontend/src/data/mock/hanyangPath.json b/uniro_frontend/src/data/mock/hanyangPath.json index 9c4d75f..5c3ebb4 100644 --- a/uniro_frontend/src/data/mock/hanyangPath.json +++ b/uniro_frontend/src/data/mock/hanyangPath.json @@ -1,2721 +1,2721 @@ { - "path0": [ - { - "id": "0", - "lat": 37.557564, - "lng": 127.042027 - }, - { - "id": "1", - "lat": 37.55759, - "lng": 127.042023 - }, - { - "id": "2", - "lat": 37.557617, - "lng": 127.042018 - }, - { - "id": "3", - "lat": 37.557643, - "lng": 127.042012 - }, - { - "id": "4", - "lat": 37.557669, - "lng": 127.042007 - }, - { - "id": "5", - "lat": 37.557695, - "lng": 127.042002 - }, - { - "id": "6", - "lat": 37.557721, - "lng": 127.041997 - }, - { - "id": "7", - "lat": 37.557747, - "lng": 127.041992 - }, - { - "id": "8", - "lat": 37.557774, - "lng": 127.041986 - }, - { - "id": "9", - "lat": 37.5578, - "lng": 127.041981 - }, - { - "id": "10", - "lat": 37.557826, - "lng": 127.041976 - }, - { - "id": "11", - "lat": 37.557852, - "lng": 127.041971 - }, - { - "id": "12", - "lat": 37.557878, - "lng": 127.041966 - }, - { - "id": "13", - "lat": 37.557904, - "lng": 127.041961 - }, - { - "id": "14", - "lat": 37.55793, - "lng": 127.041955 - }, - { - "id": "15", - "lat": 37.557947, - "lng": 127.041952 - } - ], - "path1": [ - { - "id": "0", - "lat": 37.557947, - "lng": 127.041952 - }, - { - "id": "1", - "lat": 37.557949, - "lng": 127.041986 - }, - { - "id": "2", - "lat": 37.55795, - "lng": 127.04202 - }, - { - "id": "3", - "lat": 37.55795, - "lng": 127.042052 - }, - { - "id": "4", - "lat": 37.557951, - "lng": 127.042086 - }, - { - "id": "5", - "lat": 37.557952, - "lng": 127.042118 - }, - { - "id": "6", - "lat": 37.557953, - "lng": 127.04215 - }, - { - "id": "7", - "lat": 37.557953, - "lng": 127.042183 - }, - { - "id": "8", - "lat": 37.557954, - "lng": 127.042216 - }, - { - "id": "9", - "lat": 37.557955, - "lng": 127.042247 - }, - { - "id": "10", - "lat": 37.557956, - "lng": 127.04228 - }, - { - "id": "11", - "lat": 37.557956, - "lng": 127.042314 - }, - { - "id": "12", - "lat": 37.557957, - "lng": 127.042345 - }, - { - "id": "13", - "lat": 37.557958, - "lng": 127.042377 - }, - { - "id": "14", - "lat": 37.557959, - "lng": 127.04241 - }, - { - "id": "15", - "lat": 37.557959, - "lng": 127.042443 - }, - { - "id": "16", - "lat": 37.55796, - "lng": 127.042475 - }, - { - "id": "17", - "lat": 37.557961, - "lng": 127.042507 - }, - { - "id": "18", - "lat": 37.557962, - "lng": 127.042539 - }, - { - "id": "19", - "lat": 37.557962, - "lng": 127.042573 - }, - { - "id": "20", - "lat": 37.557963, - "lng": 127.042607 - }, - { - "id": "21", - "lat": 37.557964, - "lng": 127.04264 - }, - { - "id": "22", - "lat": 37.557965, - "lng": 127.042673 - }, - { - "id": "23", - "lat": 37.557965, - "lng": 127.042706 - }, - { - "id": "24", - "lat": 37.557966, - "lng": 127.04274 - }, - { - "id": "25", - "lat": 37.557967, - "lng": 127.042774 - }, - { - "id": "26", - "lat": 37.557967, - "lng": 127.042795 - } - ], - "path2": [ - { - "id": "0", - "lat": 37.557967, - "lng": 127.042795 - }, - { - "id": "1", - "lat": 37.557945, - "lng": 127.042778 - }, - { - "id": "2", - "lat": 37.557923, - "lng": 127.04276 - }, - { - "id": "3", - "lat": 37.5579, - "lng": 127.042742 - }, - { - "id": "4", - "lat": 37.557878, - "lng": 127.042724 - }, - { - "id": "5", - "lat": 37.557855, - "lng": 127.042706 - }, - { - "id": "6", - "lat": 37.557833, - "lng": 127.042688 - }, - { - "id": "7", - "lat": 37.557811, - "lng": 127.042671 - }, - { - "id": "8", - "lat": 37.55779, - "lng": 127.042653 - }, - { - "id": "9", - "lat": 37.557767, - "lng": 127.042635 - }, - { - "id": "10", - "lat": 37.557745, - "lng": 127.042617 - }, - { - "id": "11", - "lat": 37.557724, - "lng": 127.0426 - }, - { - "id": "12", - "lat": 37.557703, - "lng": 127.042583 - }, - { - "id": "13", - "lat": 37.557681, - "lng": 127.042566 - }, - { - "id": "14", - "lat": 37.557659, - "lng": 127.042548 - }, - { - "id": "15", - "lat": 37.557637, - "lng": 127.04253 - }, - { - "id": "16", - "lat": 37.557615, - "lng": 127.042513 - }, - { - "id": "17", - "lat": 37.557592, - "lng": 127.042495 - }, - { - "id": "18", - "lat": 37.55757, - "lng": 127.042477 - }, - { - "id": "19", - "lat": 37.557548, - "lng": 127.042459 - }, - { - "id": "20", - "lat": 37.557527, - "lng": 127.042442 - } - ], - "path3": [ - { - "id": "0", - "lat": 37.557527, - "lng": 127.042442 - }, - { - "id": "1", - "lat": 37.557992, - "lng": 127.042813 - }, - { - "id": "2", - "lat": 37.558017, - "lng": 127.042824 - }, - { - "id": "3", - "lat": 37.558042, - "lng": 127.042836 - }, - { - "id": "4", - "lat": 37.558067, - "lng": 127.042847 - }, - { - "id": "5", - "lat": 37.558093, - "lng": 127.042859 - }, - { - "id": "6", - "lat": 37.558118, - "lng": 127.042867 - }, - { - "id": "7", - "lat": 37.558141, - "lng": 127.042851 - }, - { - "id": "8", - "lat": 37.558164, - "lng": 127.042837 - }, - { - "id": "9", - "lat": 37.558188, - "lng": 127.042823 - }, - { - "id": "10", - "lat": 37.558212, - "lng": 127.042808 - }, - { - "id": "11", - "lat": 37.558236, - "lng": 127.042794 - }, - { - "id": "12", - "lat": 37.558259, - "lng": 127.042776 - }, - { - "id": "13", - "lat": 37.558281, - "lng": 127.042756 - }, - { - "id": "14", - "lat": 37.558301, - "lng": 127.042735 - }, - { - "id": "15", - "lat": 37.558312, - "lng": 127.042705 - }, - { - "id": "16", - "lat": 37.558321, - "lng": 127.042674 - }, - { - "id": "17", - "lat": 37.558331, - "lng": 127.042645 - }, - { - "id": "18", - "lat": 37.558339, - "lng": 127.042614 - }, - { - "id": "19", - "lat": 37.558343, - "lng": 127.042582 - }, - { - "id": "20", - "lat": 37.558346, - "lng": 127.042549 - }, - { - "id": "21", - "lat": 37.558348, - "lng": 127.042516 - }, - { - "id": "22", - "lat": 37.558354, - "lng": 127.042484 - }, - { - "id": "23", - "lat": 37.558367, - "lng": 127.042459 - }, - { - "id": "24", - "lat": 37.558392, - "lng": 127.042448 - }, - { - "id": "25", - "lat": 37.558419, - "lng": 127.042442 - }, - { - "id": "26", - "lat": 37.558445, - "lng": 127.04244 - }, - { - "id": "27", - "lat": 37.558471, - "lng": 127.042438 - }, - { - "id": "28", - "lat": 37.558497, - "lng": 127.042436 - }, - { - "id": "29", - "lat": 37.558524, - "lng": 127.042434 - }, - { - "id": "30", - "lat": 37.55855, - "lng": 127.042433 - }, - { - "id": "31", - "lat": 37.558577, - "lng": 127.042431 - }, - { - "id": "32", - "lat": 37.558603, - "lng": 127.042429 - }, - { - "id": "33", - "lat": 37.558629, - "lng": 127.042427 - }, - { - "id": "34", - "lat": 37.558655, - "lng": 127.042425 - }, - { - "id": "35", - "lat": 37.558682, - "lng": 127.042423 - }, - { - "id": "36", - "lat": 37.558708, - "lng": 127.042421 - }, - { - "id": "37", - "lat": 37.558735, - "lng": 127.04242 - }, - { - "id": "38", - "lat": 37.558756, - "lng": 127.042418 - } - ], - "path4": [ - { - "id": "0", - "lat": 37.557947, - "lng": 127.041952 - }, - { - "id": "1", - "lat": 37.557973, - "lng": 127.041956 - }, - { - "id": "2", - "lat": 37.557998, - "lng": 127.041953 - }, - { - "id": "3", - "lat": 37.558024, - "lng": 127.04195 - }, - { - "id": "4", - "lat": 37.558048, - "lng": 127.041947 - }, - { - "id": "5", - "lat": 37.558075, - "lng": 127.041944 - }, - { - "id": "6", - "lat": 37.5581, - "lng": 127.041942 - }, - { - "id": "7", - "lat": 37.558125, - "lng": 127.041939 - }, - { - "id": "8", - "lat": 37.558149, - "lng": 127.041936 - }, - { - "id": "9", - "lat": 37.558174, - "lng": 127.041933 - }, - { - "id": "10", - "lat": 37.558199, - "lng": 127.04193 - }, - { - "id": "11", - "lat": 37.558223, - "lng": 127.041928 - }, - { - "id": "12", - "lat": 37.558248, - "lng": 127.041925 - }, - { - "id": "13", - "lat": 37.558272, - "lng": 127.041922 - }, - { - "id": "14", - "lat": 37.558296, - "lng": 127.041919 - }, - { - "id": "15", - "lat": 37.558321, - "lng": 127.041916 - }, - { - "id": "16", - "lat": 37.558344, - "lng": 127.041914 - }, - { - "id": "17", - "lat": 37.558369, - "lng": 127.041911 - }, - { - "id": "18", - "lat": 37.558394, - "lng": 127.041908 - }, - { - "id": "19", - "lat": 37.558419, - "lng": 127.041905 - }, - { - "id": "20", - "lat": 37.558444, - "lng": 127.041903 - }, - { - "id": "21", - "lat": 37.55847, - "lng": 127.0419 - }, - { - "id": "22", - "lat": 37.558496, - "lng": 127.041897 - }, - { - "id": "23", - "lat": 37.55852, - "lng": 127.041894 - }, - { - "id": "24", - "lat": 37.558546, - "lng": 127.041891 - }, - { - "id": "25", - "lat": 37.558573, - "lng": 127.041888 - }, - { - "id": "26", - "lat": 37.558598, - "lng": 127.041885 - }, - { - "id": "27", - "lat": 37.558623, - "lng": 127.041882 - }, - { - "id": "28", - "lat": 37.558649, - "lng": 127.041879 - }, - { - "id": "29", - "lat": 37.558673, - "lng": 127.041877 - }, - { - "id": "30", - "lat": 37.558698, - "lng": 127.041874 - }, - { - "id": "31", - "lat": 37.558723, - "lng": 127.041871 - }, - { - "id": "32", - "lat": 37.558748, - "lng": 127.041868 - }, - { - "id": "33", - "lat": 37.558775, - "lng": 127.041865 - }, - { - "id": "34", - "lat": 37.558801, - "lng": 127.041862 - }, - { - "id": "35", - "lat": 37.558825, - "lng": 127.041859 - }, - { - "id": "36", - "lat": 37.558848, - "lng": 127.041857 - }, - { - "id": "37", - "lat": 37.558874, - "lng": 127.041854 - }, - { - "id": "38", - "lat": 37.558898, - "lng": 127.041851 - }, - { - "id": "39", - "lat": 37.558922, - "lng": 127.041848 - }, - { - "id": "40", - "lat": 37.558949, - "lng": 127.041845 - }, - { - "id": "41", - "lat": 37.558975, - "lng": 127.041842 - }, - { - "id": "42", - "lat": 37.559001, - "lng": 127.04184 - }, - { - "id": "43", - "lat": 37.559026, - "lng": 127.041837 - }, - { - "id": "44", - "lat": 37.559052, - "lng": 127.041834 - }, - { - "id": "45", - "lat": 37.559078, - "lng": 127.041831 - }, - { - "id": "46", - "lat": 37.559104, - "lng": 127.041828 - }, - { - "id": "47", - "lat": 37.559131, - "lng": 127.041834 - }, - { - "id": "48", - "lat": 37.559157, - "lng": 127.041841 - }, - { - "id": "49", - "lat": 37.559183, - "lng": 127.041849 - }, - { - "id": "50", - "lat": 37.559209, - "lng": 127.041859 - }, - { - "id": "51", - "lat": 37.559232, - "lng": 127.041874 - }, - { - "id": "52", - "lat": 37.559256, - "lng": 127.04189 - }, - { - "id": "53", - "lat": 37.55928, - "lng": 127.041906 - }, - { - "id": "54", - "lat": 37.5593, - "lng": 127.041925 - }, - { - "id": "55", - "lat": 37.559316, - "lng": 127.041953 - }, - { - "id": "56", - "lat": 37.559331, - "lng": 127.04198 - }, - { - "id": "57", - "lat": 37.559347, - "lng": 127.042007 - }, - { - "id": "58", - "lat": 37.559362, - "lng": 127.042035 - }, - { - "id": "59", - "lat": 37.559378, - "lng": 127.042062 - }, - { - "id": "60", - "lat": 37.559393, - "lng": 127.04209 - }, - { - "id": "61", - "lat": 37.559411, - "lng": 127.042115 - }, - { - "id": "62", - "lat": 37.559423, - "lng": 127.04213 - } - ], - "path5": [ - { - "id": "0", - "lat": 37.559423, - "lng": 127.04213 - }, - { - "id": "1", - "lat": 37.55945, - "lng": 127.042126 - }, - { - "id": "2", - "lat": 37.559476, - "lng": 127.042123 - }, - { - "id": "3", - "lat": 37.559502, - "lng": 127.042121 - }, - { - "id": "4", - "lat": 37.559529, - "lng": 127.042118 - }, - { - "id": "5", - "lat": 37.559556, - "lng": 127.042115 - }, - { - "id": "6", - "lat": 37.559582, - "lng": 127.042112 - }, - { - "id": "7", - "lat": 37.559608, - "lng": 127.042109 - }, - { - "id": "8", - "lat": 37.559635, - "lng": 127.042106 - }, - { - "id": "9", - "lat": 37.559649, - "lng": 127.042105 - } - ], - "path6": [ - { - "id": "0", - "lat": 37.559649, - "lng": 127.042105 - }, - { - "id": "1", - "lat": 37.559651, - "lng": 127.042143 - }, - { - "id": "2", - "lat": 37.559652, - "lng": 127.042177 - }, - { - "id": "3", - "lat": 37.559652, - "lng": 127.04221 - }, - { - "id": "4", - "lat": 37.559652, - "lng": 127.042244 - }, - { - "id": "5", - "lat": 37.559652, - "lng": 127.042277 - }, - { - "id": "6", - "lat": 37.559653, - "lng": 127.042309 - }, - { - "id": "7", - "lat": 37.559653, - "lng": 127.042341 - }, - { - "id": "8", - "lat": 37.559653, - "lng": 127.042373 - }, - { - "id": "9", - "lat": 37.559654, - "lng": 127.042406 - }, - { - "id": "10", - "lat": 37.559654, - "lng": 127.04244 - }, - { - "id": "11", - "lat": 37.559654, - "lng": 127.042472 - }, - { - "id": "12", - "lat": 37.559654, - "lng": 127.042506 - }, - { - "id": "13", - "lat": 37.559655, - "lng": 127.04254 - }, - { - "id": "14", - "lat": 37.559655, - "lng": 127.04257 - }, - { - "id": "15", - "lat": 37.559655, - "lng": 127.042603 - }, - { - "id": "16", - "lat": 37.559656, - "lng": 127.042635 - }, - { - "id": "17", - "lat": 37.559656, - "lng": 127.042667 - }, - { - "id": "18", - "lat": 37.559656, - "lng": 127.042699 - }, - { - "id": "19", - "lat": 37.559656, - "lng": 127.04273 - }, - { - "id": "20", - "lat": 37.559657, - "lng": 127.042761 - }, - { - "id": "21", - "lat": 37.559657, - "lng": 127.042794 - }, - { - "id": "22", - "lat": 37.559657, - "lng": 127.042827 - }, - { - "id": "23", - "lat": 37.559658, - "lng": 127.042859 - }, - { - "id": "24", - "lat": 37.559658, - "lng": 127.042891 - }, - { - "id": "25", - "lat": 37.559658, - "lng": 127.042923 - }, - { - "id": "26", - "lat": 37.559658, - "lng": 127.042956 - }, - { - "id": "27", - "lat": 37.559659, - "lng": 127.042989 - }, - { - "id": "28", - "lat": 37.559659, - "lng": 127.043022 - }, - { - "id": "29", - "lat": 37.559659, - "lng": 127.043056 - }, - { - "id": "30", - "lat": 37.559659, - "lng": 127.043084 - } - ], - "path7": [ - { - "id": "0", - "lat": 37.559423, - "lng": 127.04213 - }, - { - "id": "1", - "lat": 37.559405, - "lng": 127.04216 - }, - { - "id": "2", - "lat": 37.559391, - "lng": 127.042188 - }, - { - "id": "3", - "lat": 37.559385, - "lng": 127.042221 - }, - { - "id": "4", - "lat": 37.55938, - "lng": 127.042254 - }, - { - "id": "5", - "lat": 37.559375, - "lng": 127.042288 - }, - { - "id": "6", - "lat": 37.559371, - "lng": 127.042321 - }, - { - "id": "7", - "lat": 37.559368, - "lng": 127.042354 - }, - { - "id": "8", - "lat": 37.559365, - "lng": 127.042388 - }, - { - "id": "9", - "lat": 37.559362, - "lng": 127.042421 - }, - { - "id": "10", - "lat": 37.559358, - "lng": 127.042455 - }, - { - "id": "11", - "lat": 37.559355, - "lng": 127.042489 - }, - { - "id": "12", - "lat": 37.559352, - "lng": 127.042522 - }, - { - "id": "13", - "lat": 37.559348, - "lng": 127.042555 - }, - { - "id": "14", - "lat": 37.559344, - "lng": 127.042589 - }, - { - "id": "15", - "lat": 37.55934, - "lng": 127.042622 - }, - { - "id": "16", - "lat": 37.559336, - "lng": 127.042655 - }, - { - "id": "17", - "lat": 37.559332, - "lng": 127.042689 - }, - { - "id": "18", - "lat": 37.559328, - "lng": 127.042722 - }, - { - "id": "19", - "lat": 37.559324, - "lng": 127.042755 - }, - { - "id": "20", - "lat": 37.55932, - "lng": 127.042788 - }, - { - "id": "21", - "lat": 37.559316, - "lng": 127.042821 - }, - { - "id": "22", - "lat": 37.559311, - "lng": 127.042854 - }, - { - "id": "23", - "lat": 37.559305, - "lng": 127.042887 - }, - { - "id": "24", - "lat": 37.559299, - "lng": 127.04292 - }, - { - "id": "25", - "lat": 37.559292, - "lng": 127.042952 - }, - { - "id": "26", - "lat": 37.559286, - "lng": 127.042985 - }, - { - "id": "27", - "lat": 37.559279, - "lng": 127.043017 - }, - { - "id": "28", - "lat": 37.559273, - "lng": 127.04305 - }, - { - "id": "29", - "lat": 37.559263, - "lng": 127.043082 - }, - { - "id": "30", - "lat": 37.559252, - "lng": 127.043113 - }, - { - "id": "31", - "lat": 37.559242, - "lng": 127.043144 - }, - { - "id": "32", - "lat": 37.559232, - "lng": 127.043175 - }, - { - "id": "33", - "lat": 37.559223, - "lng": 127.043207 - }, - { - "id": "34", - "lat": 37.559213, - "lng": 127.043239 - }, - { - "id": "35", - "lat": 37.559205, - "lng": 127.043271 - }, - { - "id": "36", - "lat": 37.559201, - "lng": 127.043304 - }, - { - "id": "37", - "lat": 37.559196, - "lng": 127.043338 - }, - { - "id": "38", - "lat": 37.559191, - "lng": 127.043371 - }, - { - "id": "39", - "lat": 37.559186, - "lng": 127.043404 - }, - { - "id": "40", - "lat": 37.559185, - "lng": 127.043438 - }, - { - "id": "41", - "lat": 37.559184, - "lng": 127.043471 - }, - { - "id": "42", - "lat": 37.559183, - "lng": 127.043505 - }, - { - "id": "43", - "lat": 37.559182, - "lng": 127.043539 - }, - { - "id": "44", - "lat": 37.559182, - "lng": 127.043572 - }, - { - "id": "45", - "lat": 37.55919, - "lng": 127.043605 - }, - { - "id": "46", - "lat": 37.559197, - "lng": 127.043637 - }, - { - "id": "47", - "lat": 37.559207, - "lng": 127.043668 - }, - { - "id": "48", - "lat": 37.559224, - "lng": 127.043695 - }, - { - "id": "49", - "lat": 37.559248, - "lng": 127.043706 - }, - { - "id": "50", - "lat": 37.559275, - "lng": 127.043711 - }, - { - "id": "51", - "lat": 37.559301, - "lng": 127.043705 - }, - { - "id": "52", - "lat": 37.559327, - "lng": 127.043698 - }, - { - "id": "53", - "lat": 37.559353, - "lng": 127.043691 - }, - { - "id": "54", - "lat": 37.559379, - "lng": 127.043684 - }, - { - "id": "55", - "lat": 37.559406, - "lng": 127.043677 - }, - { - "id": "56", - "lat": 37.559432, - "lng": 127.043671 - }, - { - "id": "57", - "lat": 37.559459, - "lng": 127.043666 - }, - { - "id": "58", - "lat": 37.559485, - "lng": 127.04366 - }, - { - "id": "59", - "lat": 37.559511, - "lng": 127.043654 - }, - { - "id": "60", - "lat": 37.559538, - "lng": 127.043648 - }, - { - "id": "61", - "lat": 37.559564, - "lng": 127.043643 - }, - { - "id": "62", - "lat": 37.55959, - "lng": 127.043639 - }, - { - "id": "63", - "lat": 37.559617, - "lng": 127.043636 - }, - { - "id": "64", - "lat": 37.559644, - "lng": 127.043633 - }, - { - "id": "65", - "lat": 37.55967, - "lng": 127.04363 - }, - { - "id": "66", - "lat": 37.559696, - "lng": 127.043627 - }, - { - "id": "67", - "lat": 37.559723, - "lng": 127.043624 - }, - { - "id": "68", - "lat": 37.55975, - "lng": 127.04362 - }, - { - "id": "69", - "lat": 37.559776, - "lng": 127.043617 - }, - { - "id": "70", - "lat": 37.559803, - "lng": 127.043614 - }, - { - "id": "71", - "lat": 37.55983, - "lng": 127.04361 - }, - { - "id": "72", - "lat": 37.559856, - "lng": 127.043606 - }, - { - "id": "73", - "lat": 37.559883, - "lng": 127.043603 - }, - { - "id": "74", - "lat": 37.55989, - "lng": 127.043602 - } - ], - "path8": [ - { - "id": "0", - "lat": 37.559224, - "lng": 127.043695 - }, - { - "id": "1", - "lat": 37.559195, - "lng": 127.043215 - }, - { - "id": "2", - "lat": 37.559169, - "lng": 127.043221 - }, - { - "id": "3", - "lat": 37.559143, - "lng": 127.043228 - }, - { - "id": "4", - "lat": 37.559126, - "lng": 127.043252 - }, - { - "id": "5", - "lat": 37.559113, - "lng": 127.043281 - }, - { - "id": "6", - "lat": 37.5591, - "lng": 127.043311 - }, - { - "id": "7", - "lat": 37.559094, - "lng": 127.043344 - }, - { - "id": "8", - "lat": 37.559087, - "lng": 127.043377 - }, - { - "id": "9", - "lat": 37.559082, - "lng": 127.04341 - }, - { - "id": "10", - "lat": 37.559079, - "lng": 127.043444 - }, - { - "id": "11", - "lat": 37.559075, - "lng": 127.043477 - }, - { - "id": "12", - "lat": 37.559071, - "lng": 127.04351 - }, - { - "id": "13", - "lat": 37.559068, - "lng": 127.043544 - }, - { - "id": "14", - "lat": 37.559068, - "lng": 127.043578 - }, - { - "id": "15", - "lat": 37.559071, - "lng": 127.043611 - }, - { - "id": "16", - "lat": 37.559073, - "lng": 127.043645 - }, - { - "id": "17", - "lat": 37.559075, - "lng": 127.043678 - }, - { - "id": "18", - "lat": 37.559082, - "lng": 127.043711 - }, - { - "id": "19", - "lat": 37.559092, - "lng": 127.043742 - }, - { - "id": "20", - "lat": 37.559103, - "lng": 127.043773 - }, - { - "id": "21", - "lat": 37.559111, - "lng": 127.043805 - }, - { - "id": "22", - "lat": 37.55912, - "lng": 127.043837 - }, - { - "id": "23", - "lat": 37.559128, - "lng": 127.043869 - }, - { - "id": "24", - "lat": 37.559136, - "lng": 127.0439 - }, - { - "id": "25", - "lat": 37.559144, - "lng": 127.043931 - }, - { - "id": "26", - "lat": 37.559153, - "lng": 127.043964 - }, - { - "id": "27", - "lat": 37.559161, - "lng": 127.043995 - }, - { - "id": "28", - "lat": 37.559169, - "lng": 127.044027 - }, - { - "id": "29", - "lat": 37.559177, - "lng": 127.044058 - }, - { - "id": "30", - "lat": 37.559186, - "lng": 127.044091 - }, - { - "id": "31", - "lat": 37.559192, - "lng": 127.044123 - }, - { - "id": "32", - "lat": 37.559197, - "lng": 127.044157 - }, - { - "id": "33", - "lat": 37.559202, - "lng": 127.04419 - }, - { - "id": "34", - "lat": 37.559208, - "lng": 127.044223 - }, - { - "id": "35", - "lat": 37.559213, - "lng": 127.044256 - }, - { - "id": "36", - "lat": 37.559218, - "lng": 127.044289 - }, - { - "id": "37", - "lat": 37.559224, - "lng": 127.044322 - }, - { - "id": "38", - "lat": 37.55923, - "lng": 127.044354 - }, - { - "id": "39", - "lat": 37.559236, - "lng": 127.044387 - }, - { - "id": "40", - "lat": 37.559242, - "lng": 127.044419 - }, - { - "id": "41", - "lat": 37.559248, - "lng": 127.044452 - }, - { - "id": "42", - "lat": 37.559254, - "lng": 127.044485 - }, - { - "id": "43", - "lat": 37.55926, - "lng": 127.044518 - }, - { - "id": "44", - "lat": 37.559269, - "lng": 127.04455 - }, - { - "id": "45", - "lat": 37.559281, - "lng": 127.044579 - }, - { - "id": "46", - "lat": 37.559303, - "lng": 127.044595 - } - ], - "path9": [ - { - "id": "0", - "lat": 37.559303, - "lng": 127.044595 - }, - { - "id": "1", - "lat": 37.559278, - "lng": 127.044607 - }, - { - "id": "2", - "lat": 37.559251, - "lng": 127.044611 - }, - { - "id": "3", - "lat": 37.559225, - "lng": 127.044617 - }, - { - "id": "4", - "lat": 37.559201, - "lng": 127.044628 - }, - { - "id": "5", - "lat": 37.559178, - "lng": 127.044642 - }, - { - "id": "6", - "lat": 37.559156, - "lng": 127.044661 - }, - { - "id": "7", - "lat": 37.559134, - "lng": 127.04468 - }, - { - "id": "8", - "lat": 37.559111, - "lng": 127.044699 - }, - { - "id": "9", - "lat": 37.559089, - "lng": 127.044718 - }, - { - "id": "10", - "lat": 37.559068, - "lng": 127.044737 - }, - { - "id": "11", - "lat": 37.559045, - "lng": 127.044756 - }, - { - "id": "12", - "lat": 37.559024, - "lng": 127.044775 - }, - { - "id": "13", - "lat": 37.559002, - "lng": 127.044793 - }, - { - "id": "14", - "lat": 37.55898, - "lng": 127.044812 - }, - { - "id": "15", - "lat": 37.558959, - "lng": 127.044831 - }, - { - "id": "16", - "lat": 37.558938, - "lng": 127.044849 - }, - { - "id": "17", - "lat": 37.558916, - "lng": 127.044868 - }, - { - "id": "18", - "lat": 37.558894, - "lng": 127.044887 - }, - { - "id": "19", - "lat": 37.558872, - "lng": 127.044906 - }, - { - "id": "20", - "lat": 37.55885, - "lng": 127.044924 - }, - { - "id": "21", - "lat": 37.558828, - "lng": 127.044943 - }, - { - "id": "22", - "lat": 37.558806, - "lng": 127.044963 - }, - { - "id": "23", - "lat": 37.558784, - "lng": 127.044982 - }, - { - "id": "24", - "lat": 37.558762, - "lng": 127.045001 - }, - { - "id": "25", - "lat": 37.55874, - "lng": 127.04502 - }, - { - "id": "26", - "lat": 37.558719, - "lng": 127.045039 - }, - { - "id": "27", - "lat": 37.558698, - "lng": 127.045059 - }, - { - "id": "28", - "lat": 37.558676, - "lng": 127.045078 - }, - { - "id": "29", - "lat": 37.558655, - "lng": 127.045097 - }, - { - "id": "30", - "lat": 37.558633, - "lng": 127.045117 - }, - { - "id": "31", - "lat": 37.558611, - "lng": 127.045136 - }, - { - "id": "32", - "lat": 37.55859, - "lng": 127.045156 - }, - { - "id": "33", - "lat": 37.558568, - "lng": 127.045175 - }, - { - "id": "34", - "lat": 37.558547, - "lng": 127.045195 - }, - { - "id": "35", - "lat": 37.558525, - "lng": 127.045214 - }, - { - "id": "36", - "lat": 37.558507, - "lng": 127.04523 - } - ], - "path10": [ - { - "id": "0", - "lat": 37.558507, - "lng": 127.04523 - }, - { - "id": "1", - "lat": 37.558526, - "lng": 127.045256 - }, - { - "id": "2", - "lat": 37.558545, - "lng": 127.04528 - }, - { - "id": "3", - "lat": 37.558563, - "lng": 127.045304 - }, - { - "id": "4", - "lat": 37.558582, - "lng": 127.045328 - }, - { - "id": "5", - "lat": 37.5586, - "lng": 127.045352 - }, - { - "id": "6", - "lat": 37.558619, - "lng": 127.045376 - }, - { - "id": "7", - "lat": 37.558638, - "lng": 127.0454 - }, - { - "id": "8", - "lat": 37.558657, - "lng": 127.045425 - }, - { - "id": "9", - "lat": 37.558668, - "lng": 127.045438 - } - ], - "path11": [ - { - "id": "0", - "lat": 37.558668, - "lng": 127.045438 - }, - { - "id": "1", - "lat": 37.558486, - "lng": 127.045255 - }, - { - "id": "2", - "lat": 37.558464, - "lng": 127.045275 - }, - { - "id": "3", - "lat": 37.558443, - "lng": 127.045294 - }, - { - "id": "4", - "lat": 37.558421, - "lng": 127.045313 - }, - { - "id": "5", - "lat": 37.5584, - "lng": 127.045332 - }, - { - "id": "6", - "lat": 37.558378, - "lng": 127.045352 - }, - { - "id": "7", - "lat": 37.558357, - "lng": 127.045371 - }, - { - "id": "8", - "lat": 37.558336, - "lng": 127.04539 - }, - { - "id": "9", - "lat": 37.558315, - "lng": 127.045409 - }, - { - "id": "10", - "lat": 37.558293, - "lng": 127.045428 - }, - { - "id": "11", - "lat": 37.558273, - "lng": 127.045446 - }, - { - "id": "12", - "lat": 37.558251, - "lng": 127.045466 - }, - { - "id": "13", - "lat": 37.55823, - "lng": 127.045485 - }, - { - "id": "14", - "lat": 37.558209, - "lng": 127.045503 - }, - { - "id": "15", - "lat": 37.558188, - "lng": 127.045522 - }, - { - "id": "16", - "lat": 37.558167, - "lng": 127.045542 - }, - { - "id": "17", - "lat": 37.558146, - "lng": 127.04556 - }, - { - "id": "18", - "lat": 37.558125, - "lng": 127.045579 - }, - { - "id": "19", - "lat": 37.558103, - "lng": 127.045599 - }, - { - "id": "20", - "lat": 37.558082, - "lng": 127.045618 - }, - { - "id": "21", - "lat": 37.55806, - "lng": 127.045637 - }, - { - "id": "22", - "lat": 37.558038, - "lng": 127.045657 - }, - { - "id": "23", - "lat": 37.558017, - "lng": 127.045675 - }, - { - "id": "24", - "lat": 37.558008, - "lng": 127.045683 - } - ], - "path12": [ - { - "id": "0", - "lat": 37.558507, - "lng": 127.04523 - }, - { - "id": "1", - "lat": 37.559332, - "lng": 127.044605 - }, - { - "id": "2", - "lat": 37.559359, - "lng": 127.044609 - }, - { - "id": "3", - "lat": 37.559386, - "lng": 127.044612 - }, - { - "id": "4", - "lat": 37.559412, - "lng": 127.044616 - }, - { - "id": "5", - "lat": 37.559439, - "lng": 127.044619 - }, - { - "id": "6", - "lat": 37.559465, - "lng": 127.044622 - }, - { - "id": "7", - "lat": 37.559492, - "lng": 127.044626 - }, - { - "id": "8", - "lat": 37.559517, - "lng": 127.044629 - } - ], - "path13": [ - { - "id": "0", - "lat": 37.559517, - "lng": 127.044629 - }, - { - "id": "1", - "lat": 37.559518, - "lng": 127.044593 - }, - { - "id": "2", - "lat": 37.559516, - "lng": 127.044559 - }, - { - "id": "3", - "lat": 37.559514, - "lng": 127.044526 - }, - { - "id": "4", - "lat": 37.559513, - "lng": 127.044492 - }, - { - "id": "5", - "lat": 37.559511, - "lng": 127.044459 - }, - { - "id": "6", - "lat": 37.559509, - "lng": 127.044425 - }, - { - "id": "7", - "lat": 37.559507, - "lng": 127.044391 - } - ], - "path14": [ - { - "id": "0", - "lat": 37.559517, - "lng": 127.044629 - }, - { - "id": "1", - "lat": 37.559513, - "lng": 127.044665 - }, - { - "id": "2", - "lat": 37.559509, - "lng": 127.044698 - }, - { - "id": "3", - "lat": 37.559505, - "lng": 127.044732 - }, - { - "id": "4", - "lat": 37.559501, - "lng": 127.044765 - }, - { - "id": "5", - "lat": 37.559498, - "lng": 127.044797 - }, - { - "id": "6", - "lat": 37.559494, - "lng": 127.044831 - }, - { - "id": "7", - "lat": 37.55949, - "lng": 127.044864 - }, - { - "id": "8", - "lat": 37.559486, - "lng": 127.044897 - }, - { - "id": "9", - "lat": 37.559483, - "lng": 127.04493 - }, - { - "id": "10", - "lat": 37.559479, - "lng": 127.044964 - }, - { - "id": "11", - "lat": 37.55946, - "lng": 127.044986 - }, - { - "id": "12", - "lat": 37.559439, - "lng": 127.045007 - }, - { - "id": "13", - "lat": 37.559418, - "lng": 127.045028 - }, - { - "id": "14", - "lat": 37.559397, - "lng": 127.045049 - }, - { - "id": "15", - "lat": 37.559377, - "lng": 127.045069 - }, - { - "id": "16", - "lat": 37.559357, - "lng": 127.045089 - }, - { - "id": "17", - "lat": 37.559337, - "lng": 127.04511 - }, - { - "id": "18", - "lat": 37.559317, - "lng": 127.045131 - }, - { - "id": "19", - "lat": 37.559296, - "lng": 127.045152 - }, - { - "id": "20", - "lat": 37.559276, - "lng": 127.045172 - }, - { - "id": "21", - "lat": 37.559255, - "lng": 127.045193 - }, - { - "id": "22", - "lat": 37.559234, - "lng": 127.045214 - }, - { - "id": "23", - "lat": 37.559214, - "lng": 127.045235 - }, - { - "id": "24", - "lat": 37.559193, - "lng": 127.045256 - }, - { - "id": "25", - "lat": 37.559173, - "lng": 127.045276 - }, - { - "id": "26", - "lat": 37.559153, - "lng": 127.045296 - }, - { - "id": "27", - "lat": 37.559133, - "lng": 127.045316 - }, - { - "id": "28", - "lat": 37.559112, - "lng": 127.045337 - }, - { - "id": "29", - "lat": 37.559092, - "lng": 127.045358 - }, - { - "id": "30", - "lat": 37.559072, - "lng": 127.045378 - }, - { - "id": "31", - "lat": 37.559051, - "lng": 127.045399 - }, - { - "id": "32", - "lat": 37.559031, - "lng": 127.045419 - }, - { - "id": "33", - "lat": 37.559011, - "lng": 127.045439 - }, - { - "id": "34", - "lat": 37.558991, - "lng": 127.04546 - }, - { - "id": "35", - "lat": 37.558971, - "lng": 127.04548 - }, - { - "id": "36", - "lat": 37.55895, - "lng": 127.045501 - }, - { - "id": "37", - "lat": 37.558931, - "lng": 127.045521 - }, - { - "id": "38", - "lat": 37.55891, - "lng": 127.045542 - }, - { - "id": "39", - "lat": 37.558891, - "lng": 127.045563 - }, - { - "id": "40", - "lat": 37.558872, - "lng": 127.045586 - }, - { - "id": "41", - "lat": 37.558853, - "lng": 127.045609 - }, - { - "id": "42", - "lat": 37.558834, - "lng": 127.045633 - }, - { - "id": "43", - "lat": 37.558816, - "lng": 127.045655 - }, - { - "id": "44", - "lat": 37.558797, - "lng": 127.045678 - }, - { - "id": "45", - "lat": 37.558778, - "lng": 127.045701 - }, - { - "id": "46", - "lat": 37.55876, - "lng": 127.045723 - }, - { - "id": "47", - "lat": 37.558741, - "lng": 127.045747 - }, - { - "id": "48", - "lat": 37.558723, - "lng": 127.045769 - }, - { - "id": "49", - "lat": 37.558704, - "lng": 127.045792 - }, - { - "id": "50", - "lat": 37.558686, - "lng": 127.045814 - }, - { - "id": "51", - "lat": 37.558668, - "lng": 127.045836 - }, - { - "id": "52", - "lat": 37.558649, - "lng": 127.04586 - }, - { - "id": "53", - "lat": 37.558629, - "lng": 127.045883 - }, - { - "id": "54", - "lat": 37.558612, - "lng": 127.045904 - }, - { - "id": "55", - "lat": 37.558594, - "lng": 127.045927 - }, - { - "id": "56", - "lat": 37.558576, - "lng": 127.045949 - }, - { - "id": "57", - "lat": 37.558557, - "lng": 127.045972 - }, - { - "id": "58", - "lat": 37.558539, - "lng": 127.045994 - }, - { - "id": "59", - "lat": 37.558521, - "lng": 127.046017 - }, - { - "id": "60", - "lat": 37.558503, - "lng": 127.046038 - }, - { - "id": "61", - "lat": 37.558485, - "lng": 127.04606 - }, - { - "id": "62", - "lat": 37.558466, - "lng": 127.046084 - }, - { - "id": "63", - "lat": 37.558448, - "lng": 127.046105 - }, - { - "id": "64", - "lat": 37.55843, - "lng": 127.046128 - }, - { - "id": "65", - "lat": 37.558412, - "lng": 127.04615 - }, - { - "id": "66", - "lat": 37.558393, - "lng": 127.046173 - }, - { - "id": "67", - "lat": 37.558374, - "lng": 127.046196 - }, - { - "id": "68", - "lat": 37.558356, - "lng": 127.046218 - }, - { - "id": "69", - "lat": 37.558338, - "lng": 127.046241 - }, - { - "id": "70", - "lat": 37.558319, - "lng": 127.046264 - }, - { - "id": "71", - "lat": 37.5583, - "lng": 127.046288 - }, - { - "id": "72", - "lat": 37.558281, - "lng": 127.046311 - } - ], - "path15": [ - { - "id": "0", - "lat": 37.558018, - "lng": 127.045677 - }, - { - "id": "1", - "lat": 37.558025, - "lng": 127.045709 - }, - { - "id": "2", - "lat": 37.558032, - "lng": 127.045742 - }, - { - "id": "3", - "lat": 37.558039, - "lng": 127.045774 - }, - { - "id": "4", - "lat": 37.558046, - "lng": 127.045807 - }, - { - "id": "5", - "lat": 37.558053, - "lng": 127.04584 - }, - { - "id": "6", - "lat": 37.558059, - "lng": 127.045872 - }, - { - "id": "7", - "lat": 37.558066, - "lng": 127.045905 - }, - { - "id": "8", - "lat": 37.558073, - "lng": 127.045938 - }, - { - "id": "9", - "lat": 37.55808, - "lng": 127.04597 - }, - { - "id": "10", - "lat": 37.558092, - "lng": 127.046 - }, - { - "id": "11", - "lat": 37.558105, - "lng": 127.04603 - }, - { - "id": "12", - "lat": 37.558119, - "lng": 127.046059 - }, - { - "id": "13", - "lat": 37.558132, - "lng": 127.046088 - }, - { - "id": "14", - "lat": 37.558145, - "lng": 127.046117 - }, - { - "id": "15", - "lat": 37.558158, - "lng": 127.046146 - }, - { - "id": "16", - "lat": 37.558171, - "lng": 127.046175 - }, - { - "id": "17", - "lat": 37.558184, - "lng": 127.046204 - }, - { - "id": "18", - "lat": 37.558198, - "lng": 127.046234 - }, - { - "id": "19", - "lat": 37.558216, - "lng": 127.046258 - }, - { - "id": "20", - "lat": 37.558237, - "lng": 127.046279 - }, - { - "id": "21", - "lat": 37.558257, - "lng": 127.046301 - }, - { - "id": "22", - "lat": 37.558275, - "lng": 127.04632 - } - ], - "path16": [ - { - "id": "0", - "lat": 37.558008, - "lng": 127.045683 - }, - { - "id": "1", - "lat": 37.558025, - "lng": 127.045709 - }, - { - "id": "2", - "lat": 37.558032, - "lng": 127.045742 - }, - { - "id": "3", - "lat": 37.558039, - "lng": 127.045774 - }, - { - "id": "4", - "lat": 37.558046, - "lng": 127.045807 - }, - { - "id": "5", - "lat": 37.558053, - "lng": 127.04584 - }, - { - "id": "6", - "lat": 37.558059, - "lng": 127.045872 - }, - { - "id": "7", - "lat": 37.558066, - "lng": 127.045905 - }, - { - "id": "8", - "lat": 37.558073, - "lng": 127.045938 - }, - { - "id": "9", - "lat": 37.55808, - "lng": 127.04597 - }, - { - "id": "10", - "lat": 37.558092, - "lng": 127.046 - }, - { - "id": "11", - "lat": 37.558105, - "lng": 127.04603 - }, - { - "id": "12", - "lat": 37.558119, - "lng": 127.046059 - }, - { - "id": "13", - "lat": 37.558132, - "lng": 127.046088 - }, - { - "id": "14", - "lat": 37.558145, - "lng": 127.046117 - }, - { - "id": "15", - "lat": 37.558158, - "lng": 127.046146 - }, - { - "id": "16", - "lat": 37.558171, - "lng": 127.046175 - }, - { - "id": "17", - "lat": 37.558184, - "lng": 127.046204 - }, - { - "id": "18", - "lat": 37.558198, - "lng": 127.046234 - }, - { - "id": "19", - "lat": 37.558216, - "lng": 127.046258 - }, - { - "id": "20", - "lat": 37.558237, - "lng": 127.046279 - }, - { - "id": "21", - "lat": 37.558257, - "lng": 127.046301 - }, - { - "id": "22", - "lat": 37.558275, - "lng": 127.04632 - } - ] - } \ No newline at end of file + "path0": [ + { + "id": "0", + "lat": 37.557564, + "lng": 127.042027 + }, + { + "id": "1", + "lat": 37.55759, + "lng": 127.042023 + }, + { + "id": "2", + "lat": 37.557617, + "lng": 127.042018 + }, + { + "id": "3", + "lat": 37.557643, + "lng": 127.042012 + }, + { + "id": "4", + "lat": 37.557669, + "lng": 127.042007 + }, + { + "id": "5", + "lat": 37.557695, + "lng": 127.042002 + }, + { + "id": "6", + "lat": 37.557721, + "lng": 127.041997 + }, + { + "id": "7", + "lat": 37.557747, + "lng": 127.041992 + }, + { + "id": "8", + "lat": 37.557774, + "lng": 127.041986 + }, + { + "id": "9", + "lat": 37.5578, + "lng": 127.041981 + }, + { + "id": "10", + "lat": 37.557826, + "lng": 127.041976 + }, + { + "id": "11", + "lat": 37.557852, + "lng": 127.041971 + }, + { + "id": "12", + "lat": 37.557878, + "lng": 127.041966 + }, + { + "id": "13", + "lat": 37.557904, + "lng": 127.041961 + }, + { + "id": "14", + "lat": 37.55793, + "lng": 127.041955 + }, + { + "id": "15", + "lat": 37.557947, + "lng": 127.041952 + } + ], + "path1": [ + { + "id": "0", + "lat": 37.557947, + "lng": 127.041952 + }, + { + "id": "1", + "lat": 37.557949, + "lng": 127.041986 + }, + { + "id": "2", + "lat": 37.55795, + "lng": 127.04202 + }, + { + "id": "3", + "lat": 37.55795, + "lng": 127.042052 + }, + { + "id": "4", + "lat": 37.557951, + "lng": 127.042086 + }, + { + "id": "5", + "lat": 37.557952, + "lng": 127.042118 + }, + { + "id": "6", + "lat": 37.557953, + "lng": 127.04215 + }, + { + "id": "7", + "lat": 37.557953, + "lng": 127.042183 + }, + { + "id": "8", + "lat": 37.557954, + "lng": 127.042216 + }, + { + "id": "9", + "lat": 37.557955, + "lng": 127.042247 + }, + { + "id": "10", + "lat": 37.557956, + "lng": 127.04228 + }, + { + "id": "11", + "lat": 37.557956, + "lng": 127.042314 + }, + { + "id": "12", + "lat": 37.557957, + "lng": 127.042345 + }, + { + "id": "13", + "lat": 37.557958, + "lng": 127.042377 + }, + { + "id": "14", + "lat": 37.557959, + "lng": 127.04241 + }, + { + "id": "15", + "lat": 37.557959, + "lng": 127.042443 + }, + { + "id": "16", + "lat": 37.55796, + "lng": 127.042475 + }, + { + "id": "17", + "lat": 37.557961, + "lng": 127.042507 + }, + { + "id": "18", + "lat": 37.557962, + "lng": 127.042539 + }, + { + "id": "19", + "lat": 37.557962, + "lng": 127.042573 + }, + { + "id": "20", + "lat": 37.557963, + "lng": 127.042607 + }, + { + "id": "21", + "lat": 37.557964, + "lng": 127.04264 + }, + { + "id": "22", + "lat": 37.557965, + "lng": 127.042673 + }, + { + "id": "23", + "lat": 37.557965, + "lng": 127.042706 + }, + { + "id": "24", + "lat": 37.557966, + "lng": 127.04274 + }, + { + "id": "25", + "lat": 37.557967, + "lng": 127.042774 + }, + { + "id": "26", + "lat": 37.557967, + "lng": 127.042795 + } + ], + "path2": [ + { + "id": "0", + "lat": 37.557967, + "lng": 127.042795 + }, + { + "id": "1", + "lat": 37.557945, + "lng": 127.042778 + }, + { + "id": "2", + "lat": 37.557923, + "lng": 127.04276 + }, + { + "id": "3", + "lat": 37.5579, + "lng": 127.042742 + }, + { + "id": "4", + "lat": 37.557878, + "lng": 127.042724 + }, + { + "id": "5", + "lat": 37.557855, + "lng": 127.042706 + }, + { + "id": "6", + "lat": 37.557833, + "lng": 127.042688 + }, + { + "id": "7", + "lat": 37.557811, + "lng": 127.042671 + }, + { + "id": "8", + "lat": 37.55779, + "lng": 127.042653 + }, + { + "id": "9", + "lat": 37.557767, + "lng": 127.042635 + }, + { + "id": "10", + "lat": 37.557745, + "lng": 127.042617 + }, + { + "id": "11", + "lat": 37.557724, + "lng": 127.0426 + }, + { + "id": "12", + "lat": 37.557703, + "lng": 127.042583 + }, + { + "id": "13", + "lat": 37.557681, + "lng": 127.042566 + }, + { + "id": "14", + "lat": 37.557659, + "lng": 127.042548 + }, + { + "id": "15", + "lat": 37.557637, + "lng": 127.04253 + }, + { + "id": "16", + "lat": 37.557615, + "lng": 127.042513 + }, + { + "id": "17", + "lat": 37.557592, + "lng": 127.042495 + }, + { + "id": "18", + "lat": 37.55757, + "lng": 127.042477 + }, + { + "id": "19", + "lat": 37.557548, + "lng": 127.042459 + }, + { + "id": "20", + "lat": 37.557527, + "lng": 127.042442 + } + ], + "path3": [ + { + "id": "0", + "lat": 37.557527, + "lng": 127.042442 + }, + { + "id": "1", + "lat": 37.557992, + "lng": 127.042813 + }, + { + "id": "2", + "lat": 37.558017, + "lng": 127.042824 + }, + { + "id": "3", + "lat": 37.558042, + "lng": 127.042836 + }, + { + "id": "4", + "lat": 37.558067, + "lng": 127.042847 + }, + { + "id": "5", + "lat": 37.558093, + "lng": 127.042859 + }, + { + "id": "6", + "lat": 37.558118, + "lng": 127.042867 + }, + { + "id": "7", + "lat": 37.558141, + "lng": 127.042851 + }, + { + "id": "8", + "lat": 37.558164, + "lng": 127.042837 + }, + { + "id": "9", + "lat": 37.558188, + "lng": 127.042823 + }, + { + "id": "10", + "lat": 37.558212, + "lng": 127.042808 + }, + { + "id": "11", + "lat": 37.558236, + "lng": 127.042794 + }, + { + "id": "12", + "lat": 37.558259, + "lng": 127.042776 + }, + { + "id": "13", + "lat": 37.558281, + "lng": 127.042756 + }, + { + "id": "14", + "lat": 37.558301, + "lng": 127.042735 + }, + { + "id": "15", + "lat": 37.558312, + "lng": 127.042705 + }, + { + "id": "16", + "lat": 37.558321, + "lng": 127.042674 + }, + { + "id": "17", + "lat": 37.558331, + "lng": 127.042645 + }, + { + "id": "18", + "lat": 37.558339, + "lng": 127.042614 + }, + { + "id": "19", + "lat": 37.558343, + "lng": 127.042582 + }, + { + "id": "20", + "lat": 37.558346, + "lng": 127.042549 + }, + { + "id": "21", + "lat": 37.558348, + "lng": 127.042516 + }, + { + "id": "22", + "lat": 37.558354, + "lng": 127.042484 + }, + { + "id": "23", + "lat": 37.558367, + "lng": 127.042459 + }, + { + "id": "24", + "lat": 37.558392, + "lng": 127.042448 + }, + { + "id": "25", + "lat": 37.558419, + "lng": 127.042442 + }, + { + "id": "26", + "lat": 37.558445, + "lng": 127.04244 + }, + { + "id": "27", + "lat": 37.558471, + "lng": 127.042438 + }, + { + "id": "28", + "lat": 37.558497, + "lng": 127.042436 + }, + { + "id": "29", + "lat": 37.558524, + "lng": 127.042434 + }, + { + "id": "30", + "lat": 37.55855, + "lng": 127.042433 + }, + { + "id": "31", + "lat": 37.558577, + "lng": 127.042431 + }, + { + "id": "32", + "lat": 37.558603, + "lng": 127.042429 + }, + { + "id": "33", + "lat": 37.558629, + "lng": 127.042427 + }, + { + "id": "34", + "lat": 37.558655, + "lng": 127.042425 + }, + { + "id": "35", + "lat": 37.558682, + "lng": 127.042423 + }, + { + "id": "36", + "lat": 37.558708, + "lng": 127.042421 + }, + { + "id": "37", + "lat": 37.558735, + "lng": 127.04242 + }, + { + "id": "38", + "lat": 37.558756, + "lng": 127.042418 + } + ], + "path4": [ + { + "id": "0", + "lat": 37.557947, + "lng": 127.041952 + }, + { + "id": "1", + "lat": 37.557973, + "lng": 127.041956 + }, + { + "id": "2", + "lat": 37.557998, + "lng": 127.041953 + }, + { + "id": "3", + "lat": 37.558024, + "lng": 127.04195 + }, + { + "id": "4", + "lat": 37.558048, + "lng": 127.041947 + }, + { + "id": "5", + "lat": 37.558075, + "lng": 127.041944 + }, + { + "id": "6", + "lat": 37.5581, + "lng": 127.041942 + }, + { + "id": "7", + "lat": 37.558125, + "lng": 127.041939 + }, + { + "id": "8", + "lat": 37.558149, + "lng": 127.041936 + }, + { + "id": "9", + "lat": 37.558174, + "lng": 127.041933 + }, + { + "id": "10", + "lat": 37.558199, + "lng": 127.04193 + }, + { + "id": "11", + "lat": 37.558223, + "lng": 127.041928 + }, + { + "id": "12", + "lat": 37.558248, + "lng": 127.041925 + }, + { + "id": "13", + "lat": 37.558272, + "lng": 127.041922 + }, + { + "id": "14", + "lat": 37.558296, + "lng": 127.041919 + }, + { + "id": "15", + "lat": 37.558321, + "lng": 127.041916 + }, + { + "id": "16", + "lat": 37.558344, + "lng": 127.041914 + }, + { + "id": "17", + "lat": 37.558369, + "lng": 127.041911 + }, + { + "id": "18", + "lat": 37.558394, + "lng": 127.041908 + }, + { + "id": "19", + "lat": 37.558419, + "lng": 127.041905 + }, + { + "id": "20", + "lat": 37.558444, + "lng": 127.041903 + }, + { + "id": "21", + "lat": 37.55847, + "lng": 127.0419 + }, + { + "id": "22", + "lat": 37.558496, + "lng": 127.041897 + }, + { + "id": "23", + "lat": 37.55852, + "lng": 127.041894 + }, + { + "id": "24", + "lat": 37.558546, + "lng": 127.041891 + }, + { + "id": "25", + "lat": 37.558573, + "lng": 127.041888 + }, + { + "id": "26", + "lat": 37.558598, + "lng": 127.041885 + }, + { + "id": "27", + "lat": 37.558623, + "lng": 127.041882 + }, + { + "id": "28", + "lat": 37.558649, + "lng": 127.041879 + }, + { + "id": "29", + "lat": 37.558673, + "lng": 127.041877 + }, + { + "id": "30", + "lat": 37.558698, + "lng": 127.041874 + }, + { + "id": "31", + "lat": 37.558723, + "lng": 127.041871 + }, + { + "id": "32", + "lat": 37.558748, + "lng": 127.041868 + }, + { + "id": "33", + "lat": 37.558775, + "lng": 127.041865 + }, + { + "id": "34", + "lat": 37.558801, + "lng": 127.041862 + }, + { + "id": "35", + "lat": 37.558825, + "lng": 127.041859 + }, + { + "id": "36", + "lat": 37.558848, + "lng": 127.041857 + }, + { + "id": "37", + "lat": 37.558874, + "lng": 127.041854 + }, + { + "id": "38", + "lat": 37.558898, + "lng": 127.041851 + }, + { + "id": "39", + "lat": 37.558922, + "lng": 127.041848 + }, + { + "id": "40", + "lat": 37.558949, + "lng": 127.041845 + }, + { + "id": "41", + "lat": 37.558975, + "lng": 127.041842 + }, + { + "id": "42", + "lat": 37.559001, + "lng": 127.04184 + }, + { + "id": "43", + "lat": 37.559026, + "lng": 127.041837 + }, + { + "id": "44", + "lat": 37.559052, + "lng": 127.041834 + }, + { + "id": "45", + "lat": 37.559078, + "lng": 127.041831 + }, + { + "id": "46", + "lat": 37.559104, + "lng": 127.041828 + }, + { + "id": "47", + "lat": 37.559131, + "lng": 127.041834 + }, + { + "id": "48", + "lat": 37.559157, + "lng": 127.041841 + }, + { + "id": "49", + "lat": 37.559183, + "lng": 127.041849 + }, + { + "id": "50", + "lat": 37.559209, + "lng": 127.041859 + }, + { + "id": "51", + "lat": 37.559232, + "lng": 127.041874 + }, + { + "id": "52", + "lat": 37.559256, + "lng": 127.04189 + }, + { + "id": "53", + "lat": 37.55928, + "lng": 127.041906 + }, + { + "id": "54", + "lat": 37.5593, + "lng": 127.041925 + }, + { + "id": "55", + "lat": 37.559316, + "lng": 127.041953 + }, + { + "id": "56", + "lat": 37.559331, + "lng": 127.04198 + }, + { + "id": "57", + "lat": 37.559347, + "lng": 127.042007 + }, + { + "id": "58", + "lat": 37.559362, + "lng": 127.042035 + }, + { + "id": "59", + "lat": 37.559378, + "lng": 127.042062 + }, + { + "id": "60", + "lat": 37.559393, + "lng": 127.04209 + }, + { + "id": "61", + "lat": 37.559411, + "lng": 127.042115 + }, + { + "id": "62", + "lat": 37.559423, + "lng": 127.04213 + } + ], + "path5": [ + { + "id": "0", + "lat": 37.559423, + "lng": 127.04213 + }, + { + "id": "1", + "lat": 37.55945, + "lng": 127.042126 + }, + { + "id": "2", + "lat": 37.559476, + "lng": 127.042123 + }, + { + "id": "3", + "lat": 37.559502, + "lng": 127.042121 + }, + { + "id": "4", + "lat": 37.559529, + "lng": 127.042118 + }, + { + "id": "5", + "lat": 37.559556, + "lng": 127.042115 + }, + { + "id": "6", + "lat": 37.559582, + "lng": 127.042112 + }, + { + "id": "7", + "lat": 37.559608, + "lng": 127.042109 + }, + { + "id": "8", + "lat": 37.559635, + "lng": 127.042106 + }, + { + "id": "9", + "lat": 37.559649, + "lng": 127.042105 + } + ], + "path6": [ + { + "id": "0", + "lat": 37.559649, + "lng": 127.042105 + }, + { + "id": "1", + "lat": 37.559651, + "lng": 127.042143 + }, + { + "id": "2", + "lat": 37.559652, + "lng": 127.042177 + }, + { + "id": "3", + "lat": 37.559652, + "lng": 127.04221 + }, + { + "id": "4", + "lat": 37.559652, + "lng": 127.042244 + }, + { + "id": "5", + "lat": 37.559652, + "lng": 127.042277 + }, + { + "id": "6", + "lat": 37.559653, + "lng": 127.042309 + }, + { + "id": "7", + "lat": 37.559653, + "lng": 127.042341 + }, + { + "id": "8", + "lat": 37.559653, + "lng": 127.042373 + }, + { + "id": "9", + "lat": 37.559654, + "lng": 127.042406 + }, + { + "id": "10", + "lat": 37.559654, + "lng": 127.04244 + }, + { + "id": "11", + "lat": 37.559654, + "lng": 127.042472 + }, + { + "id": "12", + "lat": 37.559654, + "lng": 127.042506 + }, + { + "id": "13", + "lat": 37.559655, + "lng": 127.04254 + }, + { + "id": "14", + "lat": 37.559655, + "lng": 127.04257 + }, + { + "id": "15", + "lat": 37.559655, + "lng": 127.042603 + }, + { + "id": "16", + "lat": 37.559656, + "lng": 127.042635 + }, + { + "id": "17", + "lat": 37.559656, + "lng": 127.042667 + }, + { + "id": "18", + "lat": 37.559656, + "lng": 127.042699 + }, + { + "id": "19", + "lat": 37.559656, + "lng": 127.04273 + }, + { + "id": "20", + "lat": 37.559657, + "lng": 127.042761 + }, + { + "id": "21", + "lat": 37.559657, + "lng": 127.042794 + }, + { + "id": "22", + "lat": 37.559657, + "lng": 127.042827 + }, + { + "id": "23", + "lat": 37.559658, + "lng": 127.042859 + }, + { + "id": "24", + "lat": 37.559658, + "lng": 127.042891 + }, + { + "id": "25", + "lat": 37.559658, + "lng": 127.042923 + }, + { + "id": "26", + "lat": 37.559658, + "lng": 127.042956 + }, + { + "id": "27", + "lat": 37.559659, + "lng": 127.042989 + }, + { + "id": "28", + "lat": 37.559659, + "lng": 127.043022 + }, + { + "id": "29", + "lat": 37.559659, + "lng": 127.043056 + }, + { + "id": "30", + "lat": 37.559659, + "lng": 127.043084 + } + ], + "path7": [ + { + "id": "0", + "lat": 37.559423, + "lng": 127.04213 + }, + { + "id": "1", + "lat": 37.559405, + "lng": 127.04216 + }, + { + "id": "2", + "lat": 37.559391, + "lng": 127.042188 + }, + { + "id": "3", + "lat": 37.559385, + "lng": 127.042221 + }, + { + "id": "4", + "lat": 37.55938, + "lng": 127.042254 + }, + { + "id": "5", + "lat": 37.559375, + "lng": 127.042288 + }, + { + "id": "6", + "lat": 37.559371, + "lng": 127.042321 + }, + { + "id": "7", + "lat": 37.559368, + "lng": 127.042354 + }, + { + "id": "8", + "lat": 37.559365, + "lng": 127.042388 + }, + { + "id": "9", + "lat": 37.559362, + "lng": 127.042421 + }, + { + "id": "10", + "lat": 37.559358, + "lng": 127.042455 + }, + { + "id": "11", + "lat": 37.559355, + "lng": 127.042489 + }, + { + "id": "12", + "lat": 37.559352, + "lng": 127.042522 + }, + { + "id": "13", + "lat": 37.559348, + "lng": 127.042555 + }, + { + "id": "14", + "lat": 37.559344, + "lng": 127.042589 + }, + { + "id": "15", + "lat": 37.55934, + "lng": 127.042622 + }, + { + "id": "16", + "lat": 37.559336, + "lng": 127.042655 + }, + { + "id": "17", + "lat": 37.559332, + "lng": 127.042689 + }, + { + "id": "18", + "lat": 37.559328, + "lng": 127.042722 + }, + { + "id": "19", + "lat": 37.559324, + "lng": 127.042755 + }, + { + "id": "20", + "lat": 37.55932, + "lng": 127.042788 + }, + { + "id": "21", + "lat": 37.559316, + "lng": 127.042821 + }, + { + "id": "22", + "lat": 37.559311, + "lng": 127.042854 + }, + { + "id": "23", + "lat": 37.559305, + "lng": 127.042887 + }, + { + "id": "24", + "lat": 37.559299, + "lng": 127.04292 + }, + { + "id": "25", + "lat": 37.559292, + "lng": 127.042952 + }, + { + "id": "26", + "lat": 37.559286, + "lng": 127.042985 + }, + { + "id": "27", + "lat": 37.559279, + "lng": 127.043017 + }, + { + "id": "28", + "lat": 37.559273, + "lng": 127.04305 + }, + { + "id": "29", + "lat": 37.559263, + "lng": 127.043082 + }, + { + "id": "30", + "lat": 37.559252, + "lng": 127.043113 + }, + { + "id": "31", + "lat": 37.559242, + "lng": 127.043144 + }, + { + "id": "32", + "lat": 37.559232, + "lng": 127.043175 + }, + { + "id": "33", + "lat": 37.559223, + "lng": 127.043207 + }, + { + "id": "34", + "lat": 37.559213, + "lng": 127.043239 + }, + { + "id": "35", + "lat": 37.559205, + "lng": 127.043271 + }, + { + "id": "36", + "lat": 37.559201, + "lng": 127.043304 + }, + { + "id": "37", + "lat": 37.559196, + "lng": 127.043338 + }, + { + "id": "38", + "lat": 37.559191, + "lng": 127.043371 + }, + { + "id": "39", + "lat": 37.559186, + "lng": 127.043404 + }, + { + "id": "40", + "lat": 37.559185, + "lng": 127.043438 + }, + { + "id": "41", + "lat": 37.559184, + "lng": 127.043471 + }, + { + "id": "42", + "lat": 37.559183, + "lng": 127.043505 + }, + { + "id": "43", + "lat": 37.559182, + "lng": 127.043539 + }, + { + "id": "44", + "lat": 37.559182, + "lng": 127.043572 + }, + { + "id": "45", + "lat": 37.55919, + "lng": 127.043605 + }, + { + "id": "46", + "lat": 37.559197, + "lng": 127.043637 + }, + { + "id": "47", + "lat": 37.559207, + "lng": 127.043668 + }, + { + "id": "48", + "lat": 37.559224, + "lng": 127.043695 + }, + { + "id": "49", + "lat": 37.559248, + "lng": 127.043706 + }, + { + "id": "50", + "lat": 37.559275, + "lng": 127.043711 + }, + { + "id": "51", + "lat": 37.559301, + "lng": 127.043705 + }, + { + "id": "52", + "lat": 37.559327, + "lng": 127.043698 + }, + { + "id": "53", + "lat": 37.559353, + "lng": 127.043691 + }, + { + "id": "54", + "lat": 37.559379, + "lng": 127.043684 + }, + { + "id": "55", + "lat": 37.559406, + "lng": 127.043677 + }, + { + "id": "56", + "lat": 37.559432, + "lng": 127.043671 + }, + { + "id": "57", + "lat": 37.559459, + "lng": 127.043666 + }, + { + "id": "58", + "lat": 37.559485, + "lng": 127.04366 + }, + { + "id": "59", + "lat": 37.559511, + "lng": 127.043654 + }, + { + "id": "60", + "lat": 37.559538, + "lng": 127.043648 + }, + { + "id": "61", + "lat": 37.559564, + "lng": 127.043643 + }, + { + "id": "62", + "lat": 37.55959, + "lng": 127.043639 + }, + { + "id": "63", + "lat": 37.559617, + "lng": 127.043636 + }, + { + "id": "64", + "lat": 37.559644, + "lng": 127.043633 + }, + { + "id": "65", + "lat": 37.55967, + "lng": 127.04363 + }, + { + "id": "66", + "lat": 37.559696, + "lng": 127.043627 + }, + { + "id": "67", + "lat": 37.559723, + "lng": 127.043624 + }, + { + "id": "68", + "lat": 37.55975, + "lng": 127.04362 + }, + { + "id": "69", + "lat": 37.559776, + "lng": 127.043617 + }, + { + "id": "70", + "lat": 37.559803, + "lng": 127.043614 + }, + { + "id": "71", + "lat": 37.55983, + "lng": 127.04361 + }, + { + "id": "72", + "lat": 37.559856, + "lng": 127.043606 + }, + { + "id": "73", + "lat": 37.559883, + "lng": 127.043603 + }, + { + "id": "74", + "lat": 37.55989, + "lng": 127.043602 + } + ], + "path8": [ + { + "id": "0", + "lat": 37.559224, + "lng": 127.043695 + }, + { + "id": "1", + "lat": 37.559195, + "lng": 127.043215 + }, + { + "id": "2", + "lat": 37.559169, + "lng": 127.043221 + }, + { + "id": "3", + "lat": 37.559143, + "lng": 127.043228 + }, + { + "id": "4", + "lat": 37.559126, + "lng": 127.043252 + }, + { + "id": "5", + "lat": 37.559113, + "lng": 127.043281 + }, + { + "id": "6", + "lat": 37.5591, + "lng": 127.043311 + }, + { + "id": "7", + "lat": 37.559094, + "lng": 127.043344 + }, + { + "id": "8", + "lat": 37.559087, + "lng": 127.043377 + }, + { + "id": "9", + "lat": 37.559082, + "lng": 127.04341 + }, + { + "id": "10", + "lat": 37.559079, + "lng": 127.043444 + }, + { + "id": "11", + "lat": 37.559075, + "lng": 127.043477 + }, + { + "id": "12", + "lat": 37.559071, + "lng": 127.04351 + }, + { + "id": "13", + "lat": 37.559068, + "lng": 127.043544 + }, + { + "id": "14", + "lat": 37.559068, + "lng": 127.043578 + }, + { + "id": "15", + "lat": 37.559071, + "lng": 127.043611 + }, + { + "id": "16", + "lat": 37.559073, + "lng": 127.043645 + }, + { + "id": "17", + "lat": 37.559075, + "lng": 127.043678 + }, + { + "id": "18", + "lat": 37.559082, + "lng": 127.043711 + }, + { + "id": "19", + "lat": 37.559092, + "lng": 127.043742 + }, + { + "id": "20", + "lat": 37.559103, + "lng": 127.043773 + }, + { + "id": "21", + "lat": 37.559111, + "lng": 127.043805 + }, + { + "id": "22", + "lat": 37.55912, + "lng": 127.043837 + }, + { + "id": "23", + "lat": 37.559128, + "lng": 127.043869 + }, + { + "id": "24", + "lat": 37.559136, + "lng": 127.0439 + }, + { + "id": "25", + "lat": 37.559144, + "lng": 127.043931 + }, + { + "id": "26", + "lat": 37.559153, + "lng": 127.043964 + }, + { + "id": "27", + "lat": 37.559161, + "lng": 127.043995 + }, + { + "id": "28", + "lat": 37.559169, + "lng": 127.044027 + }, + { + "id": "29", + "lat": 37.559177, + "lng": 127.044058 + }, + { + "id": "30", + "lat": 37.559186, + "lng": 127.044091 + }, + { + "id": "31", + "lat": 37.559192, + "lng": 127.044123 + }, + { + "id": "32", + "lat": 37.559197, + "lng": 127.044157 + }, + { + "id": "33", + "lat": 37.559202, + "lng": 127.04419 + }, + { + "id": "34", + "lat": 37.559208, + "lng": 127.044223 + }, + { + "id": "35", + "lat": 37.559213, + "lng": 127.044256 + }, + { + "id": "36", + "lat": 37.559218, + "lng": 127.044289 + }, + { + "id": "37", + "lat": 37.559224, + "lng": 127.044322 + }, + { + "id": "38", + "lat": 37.55923, + "lng": 127.044354 + }, + { + "id": "39", + "lat": 37.559236, + "lng": 127.044387 + }, + { + "id": "40", + "lat": 37.559242, + "lng": 127.044419 + }, + { + "id": "41", + "lat": 37.559248, + "lng": 127.044452 + }, + { + "id": "42", + "lat": 37.559254, + "lng": 127.044485 + }, + { + "id": "43", + "lat": 37.55926, + "lng": 127.044518 + }, + { + "id": "44", + "lat": 37.559269, + "lng": 127.04455 + }, + { + "id": "45", + "lat": 37.559281, + "lng": 127.044579 + }, + { + "id": "46", + "lat": 37.559303, + "lng": 127.044595 + } + ], + "path9": [ + { + "id": "0", + "lat": 37.559303, + "lng": 127.044595 + }, + { + "id": "1", + "lat": 37.559278, + "lng": 127.044607 + }, + { + "id": "2", + "lat": 37.559251, + "lng": 127.044611 + }, + { + "id": "3", + "lat": 37.559225, + "lng": 127.044617 + }, + { + "id": "4", + "lat": 37.559201, + "lng": 127.044628 + }, + { + "id": "5", + "lat": 37.559178, + "lng": 127.044642 + }, + { + "id": "6", + "lat": 37.559156, + "lng": 127.044661 + }, + { + "id": "7", + "lat": 37.559134, + "lng": 127.04468 + }, + { + "id": "8", + "lat": 37.559111, + "lng": 127.044699 + }, + { + "id": "9", + "lat": 37.559089, + "lng": 127.044718 + }, + { + "id": "10", + "lat": 37.559068, + "lng": 127.044737 + }, + { + "id": "11", + "lat": 37.559045, + "lng": 127.044756 + }, + { + "id": "12", + "lat": 37.559024, + "lng": 127.044775 + }, + { + "id": "13", + "lat": 37.559002, + "lng": 127.044793 + }, + { + "id": "14", + "lat": 37.55898, + "lng": 127.044812 + }, + { + "id": "15", + "lat": 37.558959, + "lng": 127.044831 + }, + { + "id": "16", + "lat": 37.558938, + "lng": 127.044849 + }, + { + "id": "17", + "lat": 37.558916, + "lng": 127.044868 + }, + { + "id": "18", + "lat": 37.558894, + "lng": 127.044887 + }, + { + "id": "19", + "lat": 37.558872, + "lng": 127.044906 + }, + { + "id": "20", + "lat": 37.55885, + "lng": 127.044924 + }, + { + "id": "21", + "lat": 37.558828, + "lng": 127.044943 + }, + { + "id": "22", + "lat": 37.558806, + "lng": 127.044963 + }, + { + "id": "23", + "lat": 37.558784, + "lng": 127.044982 + }, + { + "id": "24", + "lat": 37.558762, + "lng": 127.045001 + }, + { + "id": "25", + "lat": 37.55874, + "lng": 127.04502 + }, + { + "id": "26", + "lat": 37.558719, + "lng": 127.045039 + }, + { + "id": "27", + "lat": 37.558698, + "lng": 127.045059 + }, + { + "id": "28", + "lat": 37.558676, + "lng": 127.045078 + }, + { + "id": "29", + "lat": 37.558655, + "lng": 127.045097 + }, + { + "id": "30", + "lat": 37.558633, + "lng": 127.045117 + }, + { + "id": "31", + "lat": 37.558611, + "lng": 127.045136 + }, + { + "id": "32", + "lat": 37.55859, + "lng": 127.045156 + }, + { + "id": "33", + "lat": 37.558568, + "lng": 127.045175 + }, + { + "id": "34", + "lat": 37.558547, + "lng": 127.045195 + }, + { + "id": "35", + "lat": 37.558525, + "lng": 127.045214 + }, + { + "id": "36", + "lat": 37.558507, + "lng": 127.04523 + } + ], + "path10": [ + { + "id": "0", + "lat": 37.558507, + "lng": 127.04523 + }, + { + "id": "1", + "lat": 37.558526, + "lng": 127.045256 + }, + { + "id": "2", + "lat": 37.558545, + "lng": 127.04528 + }, + { + "id": "3", + "lat": 37.558563, + "lng": 127.045304 + }, + { + "id": "4", + "lat": 37.558582, + "lng": 127.045328 + }, + { + "id": "5", + "lat": 37.5586, + "lng": 127.045352 + }, + { + "id": "6", + "lat": 37.558619, + "lng": 127.045376 + }, + { + "id": "7", + "lat": 37.558638, + "lng": 127.0454 + }, + { + "id": "8", + "lat": 37.558657, + "lng": 127.045425 + }, + { + "id": "9", + "lat": 37.558668, + "lng": 127.045438 + } + ], + "path11": [ + { + "id": "0", + "lat": 37.558668, + "lng": 127.045438 + }, + { + "id": "1", + "lat": 37.558486, + "lng": 127.045255 + }, + { + "id": "2", + "lat": 37.558464, + "lng": 127.045275 + }, + { + "id": "3", + "lat": 37.558443, + "lng": 127.045294 + }, + { + "id": "4", + "lat": 37.558421, + "lng": 127.045313 + }, + { + "id": "5", + "lat": 37.5584, + "lng": 127.045332 + }, + { + "id": "6", + "lat": 37.558378, + "lng": 127.045352 + }, + { + "id": "7", + "lat": 37.558357, + "lng": 127.045371 + }, + { + "id": "8", + "lat": 37.558336, + "lng": 127.04539 + }, + { + "id": "9", + "lat": 37.558315, + "lng": 127.045409 + }, + { + "id": "10", + "lat": 37.558293, + "lng": 127.045428 + }, + { + "id": "11", + "lat": 37.558273, + "lng": 127.045446 + }, + { + "id": "12", + "lat": 37.558251, + "lng": 127.045466 + }, + { + "id": "13", + "lat": 37.55823, + "lng": 127.045485 + }, + { + "id": "14", + "lat": 37.558209, + "lng": 127.045503 + }, + { + "id": "15", + "lat": 37.558188, + "lng": 127.045522 + }, + { + "id": "16", + "lat": 37.558167, + "lng": 127.045542 + }, + { + "id": "17", + "lat": 37.558146, + "lng": 127.04556 + }, + { + "id": "18", + "lat": 37.558125, + "lng": 127.045579 + }, + { + "id": "19", + "lat": 37.558103, + "lng": 127.045599 + }, + { + "id": "20", + "lat": 37.558082, + "lng": 127.045618 + }, + { + "id": "21", + "lat": 37.55806, + "lng": 127.045637 + }, + { + "id": "22", + "lat": 37.558038, + "lng": 127.045657 + }, + { + "id": "23", + "lat": 37.558017, + "lng": 127.045675 + }, + { + "id": "24", + "lat": 37.558008, + "lng": 127.045683 + } + ], + "path12": [ + { + "id": "0", + "lat": 37.558507, + "lng": 127.04523 + }, + { + "id": "1", + "lat": 37.559332, + "lng": 127.044605 + }, + { + "id": "2", + "lat": 37.559359, + "lng": 127.044609 + }, + { + "id": "3", + "lat": 37.559386, + "lng": 127.044612 + }, + { + "id": "4", + "lat": 37.559412, + "lng": 127.044616 + }, + { + "id": "5", + "lat": 37.559439, + "lng": 127.044619 + }, + { + "id": "6", + "lat": 37.559465, + "lng": 127.044622 + }, + { + "id": "7", + "lat": 37.559492, + "lng": 127.044626 + }, + { + "id": "8", + "lat": 37.559517, + "lng": 127.044629 + } + ], + "path13": [ + { + "id": "0", + "lat": 37.559517, + "lng": 127.044629 + }, + { + "id": "1", + "lat": 37.559518, + "lng": 127.044593 + }, + { + "id": "2", + "lat": 37.559516, + "lng": 127.044559 + }, + { + "id": "3", + "lat": 37.559514, + "lng": 127.044526 + }, + { + "id": "4", + "lat": 37.559513, + "lng": 127.044492 + }, + { + "id": "5", + "lat": 37.559511, + "lng": 127.044459 + }, + { + "id": "6", + "lat": 37.559509, + "lng": 127.044425 + }, + { + "id": "7", + "lat": 37.559507, + "lng": 127.044391 + } + ], + "path14": [ + { + "id": "0", + "lat": 37.559517, + "lng": 127.044629 + }, + { + "id": "1", + "lat": 37.559513, + "lng": 127.044665 + }, + { + "id": "2", + "lat": 37.559509, + "lng": 127.044698 + }, + { + "id": "3", + "lat": 37.559505, + "lng": 127.044732 + }, + { + "id": "4", + "lat": 37.559501, + "lng": 127.044765 + }, + { + "id": "5", + "lat": 37.559498, + "lng": 127.044797 + }, + { + "id": "6", + "lat": 37.559494, + "lng": 127.044831 + }, + { + "id": "7", + "lat": 37.55949, + "lng": 127.044864 + }, + { + "id": "8", + "lat": 37.559486, + "lng": 127.044897 + }, + { + "id": "9", + "lat": 37.559483, + "lng": 127.04493 + }, + { + "id": "10", + "lat": 37.559479, + "lng": 127.044964 + }, + { + "id": "11", + "lat": 37.55946, + "lng": 127.044986 + }, + { + "id": "12", + "lat": 37.559439, + "lng": 127.045007 + }, + { + "id": "13", + "lat": 37.559418, + "lng": 127.045028 + }, + { + "id": "14", + "lat": 37.559397, + "lng": 127.045049 + }, + { + "id": "15", + "lat": 37.559377, + "lng": 127.045069 + }, + { + "id": "16", + "lat": 37.559357, + "lng": 127.045089 + }, + { + "id": "17", + "lat": 37.559337, + "lng": 127.04511 + }, + { + "id": "18", + "lat": 37.559317, + "lng": 127.045131 + }, + { + "id": "19", + "lat": 37.559296, + "lng": 127.045152 + }, + { + "id": "20", + "lat": 37.559276, + "lng": 127.045172 + }, + { + "id": "21", + "lat": 37.559255, + "lng": 127.045193 + }, + { + "id": "22", + "lat": 37.559234, + "lng": 127.045214 + }, + { + "id": "23", + "lat": 37.559214, + "lng": 127.045235 + }, + { + "id": "24", + "lat": 37.559193, + "lng": 127.045256 + }, + { + "id": "25", + "lat": 37.559173, + "lng": 127.045276 + }, + { + "id": "26", + "lat": 37.559153, + "lng": 127.045296 + }, + { + "id": "27", + "lat": 37.559133, + "lng": 127.045316 + }, + { + "id": "28", + "lat": 37.559112, + "lng": 127.045337 + }, + { + "id": "29", + "lat": 37.559092, + "lng": 127.045358 + }, + { + "id": "30", + "lat": 37.559072, + "lng": 127.045378 + }, + { + "id": "31", + "lat": 37.559051, + "lng": 127.045399 + }, + { + "id": "32", + "lat": 37.559031, + "lng": 127.045419 + }, + { + "id": "33", + "lat": 37.559011, + "lng": 127.045439 + }, + { + "id": "34", + "lat": 37.558991, + "lng": 127.04546 + }, + { + "id": "35", + "lat": 37.558971, + "lng": 127.04548 + }, + { + "id": "36", + "lat": 37.55895, + "lng": 127.045501 + }, + { + "id": "37", + "lat": 37.558931, + "lng": 127.045521 + }, + { + "id": "38", + "lat": 37.55891, + "lng": 127.045542 + }, + { + "id": "39", + "lat": 37.558891, + "lng": 127.045563 + }, + { + "id": "40", + "lat": 37.558872, + "lng": 127.045586 + }, + { + "id": "41", + "lat": 37.558853, + "lng": 127.045609 + }, + { + "id": "42", + "lat": 37.558834, + "lng": 127.045633 + }, + { + "id": "43", + "lat": 37.558816, + "lng": 127.045655 + }, + { + "id": "44", + "lat": 37.558797, + "lng": 127.045678 + }, + { + "id": "45", + "lat": 37.558778, + "lng": 127.045701 + }, + { + "id": "46", + "lat": 37.55876, + "lng": 127.045723 + }, + { + "id": "47", + "lat": 37.558741, + "lng": 127.045747 + }, + { + "id": "48", + "lat": 37.558723, + "lng": 127.045769 + }, + { + "id": "49", + "lat": 37.558704, + "lng": 127.045792 + }, + { + "id": "50", + "lat": 37.558686, + "lng": 127.045814 + }, + { + "id": "51", + "lat": 37.558668, + "lng": 127.045836 + }, + { + "id": "52", + "lat": 37.558649, + "lng": 127.04586 + }, + { + "id": "53", + "lat": 37.558629, + "lng": 127.045883 + }, + { + "id": "54", + "lat": 37.558612, + "lng": 127.045904 + }, + { + "id": "55", + "lat": 37.558594, + "lng": 127.045927 + }, + { + "id": "56", + "lat": 37.558576, + "lng": 127.045949 + }, + { + "id": "57", + "lat": 37.558557, + "lng": 127.045972 + }, + { + "id": "58", + "lat": 37.558539, + "lng": 127.045994 + }, + { + "id": "59", + "lat": 37.558521, + "lng": 127.046017 + }, + { + "id": "60", + "lat": 37.558503, + "lng": 127.046038 + }, + { + "id": "61", + "lat": 37.558485, + "lng": 127.04606 + }, + { + "id": "62", + "lat": 37.558466, + "lng": 127.046084 + }, + { + "id": "63", + "lat": 37.558448, + "lng": 127.046105 + }, + { + "id": "64", + "lat": 37.55843, + "lng": 127.046128 + }, + { + "id": "65", + "lat": 37.558412, + "lng": 127.04615 + }, + { + "id": "66", + "lat": 37.558393, + "lng": 127.046173 + }, + { + "id": "67", + "lat": 37.558374, + "lng": 127.046196 + }, + { + "id": "68", + "lat": 37.558356, + "lng": 127.046218 + }, + { + "id": "69", + "lat": 37.558338, + "lng": 127.046241 + }, + { + "id": "70", + "lat": 37.558319, + "lng": 127.046264 + }, + { + "id": "71", + "lat": 37.5583, + "lng": 127.046288 + }, + { + "id": "72", + "lat": 37.558281, + "lng": 127.046311 + } + ], + "path15": [ + { + "id": "0", + "lat": 37.558018, + "lng": 127.045677 + }, + { + "id": "1", + "lat": 37.558025, + "lng": 127.045709 + }, + { + "id": "2", + "lat": 37.558032, + "lng": 127.045742 + }, + { + "id": "3", + "lat": 37.558039, + "lng": 127.045774 + }, + { + "id": "4", + "lat": 37.558046, + "lng": 127.045807 + }, + { + "id": "5", + "lat": 37.558053, + "lng": 127.04584 + }, + { + "id": "6", + "lat": 37.558059, + "lng": 127.045872 + }, + { + "id": "7", + "lat": 37.558066, + "lng": 127.045905 + }, + { + "id": "8", + "lat": 37.558073, + "lng": 127.045938 + }, + { + "id": "9", + "lat": 37.55808, + "lng": 127.04597 + }, + { + "id": "10", + "lat": 37.558092, + "lng": 127.046 + }, + { + "id": "11", + "lat": 37.558105, + "lng": 127.04603 + }, + { + "id": "12", + "lat": 37.558119, + "lng": 127.046059 + }, + { + "id": "13", + "lat": 37.558132, + "lng": 127.046088 + }, + { + "id": "14", + "lat": 37.558145, + "lng": 127.046117 + }, + { + "id": "15", + "lat": 37.558158, + "lng": 127.046146 + }, + { + "id": "16", + "lat": 37.558171, + "lng": 127.046175 + }, + { + "id": "17", + "lat": 37.558184, + "lng": 127.046204 + }, + { + "id": "18", + "lat": 37.558198, + "lng": 127.046234 + }, + { + "id": "19", + "lat": 37.558216, + "lng": 127.046258 + }, + { + "id": "20", + "lat": 37.558237, + "lng": 127.046279 + }, + { + "id": "21", + "lat": 37.558257, + "lng": 127.046301 + }, + { + "id": "22", + "lat": 37.558275, + "lng": 127.04632 + } + ], + "path16": [ + { + "id": "0", + "lat": 37.558008, + "lng": 127.045683 + }, + { + "id": "1", + "lat": 37.558025, + "lng": 127.045709 + }, + { + "id": "2", + "lat": 37.558032, + "lng": 127.045742 + }, + { + "id": "3", + "lat": 37.558039, + "lng": 127.045774 + }, + { + "id": "4", + "lat": 37.558046, + "lng": 127.045807 + }, + { + "id": "5", + "lat": 37.558053, + "lng": 127.04584 + }, + { + "id": "6", + "lat": 37.558059, + "lng": 127.045872 + }, + { + "id": "7", + "lat": 37.558066, + "lng": 127.045905 + }, + { + "id": "8", + "lat": 37.558073, + "lng": 127.045938 + }, + { + "id": "9", + "lat": 37.55808, + "lng": 127.04597 + }, + { + "id": "10", + "lat": 37.558092, + "lng": 127.046 + }, + { + "id": "11", + "lat": 37.558105, + "lng": 127.04603 + }, + { + "id": "12", + "lat": 37.558119, + "lng": 127.046059 + }, + { + "id": "13", + "lat": 37.558132, + "lng": 127.046088 + }, + { + "id": "14", + "lat": 37.558145, + "lng": 127.046117 + }, + { + "id": "15", + "lat": 37.558158, + "lng": 127.046146 + }, + { + "id": "16", + "lat": 37.558171, + "lng": 127.046175 + }, + { + "id": "17", + "lat": 37.558184, + "lng": 127.046204 + }, + { + "id": "18", + "lat": 37.558198, + "lng": 127.046234 + }, + { + "id": "19", + "lat": 37.558216, + "lng": 127.046258 + }, + { + "id": "20", + "lat": 37.558237, + "lng": 127.046279 + }, + { + "id": "21", + "lat": 37.558257, + "lng": 127.046301 + }, + { + "id": "22", + "lat": 37.558275, + "lng": 127.04632 + } + ] +} diff --git a/uniro_frontend/src/data/types/marker.d.ts b/uniro_frontend/src/data/types/marker.d.ts index 08d5c31..866d06c 100644 --- a/uniro_frontend/src/data/types/marker.d.ts +++ b/uniro_frontend/src/data/types/marker.d.ts @@ -2,4 +2,12 @@ import { Markers } from "../../constant/enums"; export type AdvancedMarker = google.maps.marker.AdvancedMarkerElement; -export type MarkerTypes = Markers.BUILDING | Markers.CAUTION | Markers.DANGER; +export type MarkerTypes = + | Markers.BUILDING + | Markers.CAUTION + | Markers.DANGER + | Markers.DESTINATION + | Markers.ORIGIN + | Markers.NUMBERED_WAYPOINT + | Markers.WAYPOINT + | Markers.SELECTED_BUILDING; diff --git a/uniro_frontend/src/pages/demo.tsx b/uniro_frontend/src/pages/demo.tsx index 7c8db65..96dc804 100644 --- a/uniro_frontend/src/pages/demo.tsx +++ b/uniro_frontend/src/pages/demo.tsx @@ -4,8 +4,8 @@ import LandingButton from "../components/landingButton"; import Input from "../components/customInput"; import Map from "../component/Map"; import RouteInput from "../components/map/routeSearchInput"; -import StartIcon from "../assets/map/origin.svg?react"; -import EndIcon from "../assets/map/destination.svg?react"; +import OriginIcon from "../assets/map/origin.svg?react"; +import DestinationIcon from "../assets/map/destination.svg?react"; import { useState } from "react"; import ReportButton from "../components/map/reportButton"; import { CautionToggleButton, DangerToggleButton } from "../components/map/floatingButtons"; @@ -49,16 +49,17 @@ export default function Demo() { console.log(e); }} /> - - + {}} placeholder="출발지를 입력하세요"> + {}} placeholder="도착지를 입력하세요" value={destination} onCancel={() => setDestination("")} > - +
    diff --git a/uniro_frontend/src/pages/map.tsx b/uniro_frontend/src/pages/map.tsx index bd58a24..2cd7be4 100644 --- a/uniro_frontend/src/pages/map.tsx +++ b/uniro_frontend/src/pages/map.tsx @@ -1,14 +1,7 @@ import { useEffect, useRef, useState } from "react"; import useMap from "../hooks/useMap"; import { buildings } from "../data/mock/hanyangBuildings"; -import { - buildingMarkerContent, - cautionMarkerContent, - dangerMarkerContent, - destinationMarkerContent, - originMarkerContent, - selectedBuildingMarkerContent, -} from "../components/map/mapMarkers"; +import createMarkerElement from "../components/map/mapMarkers"; import { mockHazardEdges } from "../data/mock/hanyangHazardEdge"; import { BottomSheet, BottomSheetRef } from "react-spring-bottom-sheet"; import { Building } from "../data/types/node"; @@ -24,6 +17,7 @@ import { AdvancedMarker, MarkerTypes } from "../data/types/marker"; import { RoutePointType } from "../data/types/route"; import { RoutePoint } from "../constant/enums"; import { Markers } from "../constant/enums"; +import createAdvancedMarker from "../utils/markers/createAdvanedMarker"; export type SelectedMarkerTypes = { type: MarkerTypes; @@ -32,24 +26,6 @@ export type SelectedMarkerTypes = { from: "Marker" | "List"; }; -function createAdvancedMarker( - AdvancedMarker: typeof google.maps.marker.AdvancedMarkerElement, - map: google.maps.Map, - position: google.maps.LatLng, - content: HTMLElement, - onClick: () => void, -) { - const newMarker = new AdvancedMarker({ - map: map, - position: position, - content: content, - }); - - newMarker.addListener("click", onClick); - - return newMarker; -} - export default function MapPage() { const { mapRef, map, AdvancedMarker } = useMap(); const [selectedMarker, setSelectedMarker] = useState(); @@ -74,14 +50,7 @@ export default function MapPage() { if (marker) { const { type, element } = marker; - switch (type) { - case Markers.CAUTION: - element.content = cautionMarkerContent(); - break; - case Markers.DANGER: - element.content = dangerMarkerContent(); - break; - } + element.content = createMarkerElement({ type }); } return undefined; }); @@ -99,7 +68,7 @@ export default function MapPage() { AdvancedMarker, map, new google.maps.LatLng(lat, lng), - buildingMarkerContent({ title: buildingName }), + createMarkerElement({ type: Markers.BUILDING, title: buildingName, className: "translate-marker" }), () => { setSelectedMarker({ type: Markers.BUILDING, @@ -127,11 +96,13 @@ export default function MapPage() { lat: (startNode.lat + endNode.lat) / 2, lng: (startNode.lng + endNode.lng) / 2, }), - dangerFactors ? dangerMarkerContent() : cautionMarkerContent(), + createMarkerElement({ type: dangerFactors ? Markers.DANGER : Markers.CAUTION }), () => { - hazardMarker.content = dangerFactors - ? dangerMarkerContent(dangerFactors) - : cautionMarkerContent(cautionFactors); + hazardMarker.content = createMarkerElement({ + type: dangerFactors ? Markers.DANGER : Markers.CAUTION, + title: dangerFactors ? dangerFactors[0] : cautionFactors && cautionFactors[0], + hasTopContent: true, + }); setSelectedMarker({ type: dangerFactors ? Markers.DANGER : Markers.CAUTION, element: hazardMarker, @@ -200,18 +171,23 @@ export default function MapPage() { if (!map || !selectedMarker || selectedMarker.type !== Markers.BUILDING || !selectedMarker.property) return; if (isSelect) { - marker.content = selectedBuildingMarkerContent({ + marker.content = createMarkerElement({ + type: Markers.SELECTED_BUILDING, title: selectedMarker.property.buildingName, + className: "translate-marker", }); map.setOptions({ center: { lat: selectedMarker.property.lat, lng: selectedMarker.property.lng }, zoom: 19, }); setSheetOpen(true); - } else - marker.content = buildingMarkerContent({ - title: selectedMarker.property.buildingName, - }); + + return; + } + marker.content = createMarkerElement({ + type: Markers.BUILDING, + title: selectedMarker.property.buildingName, + }); }; const findBuildingMarker = (id: string): AdvancedMarker | undefined => { @@ -258,10 +234,18 @@ export default function MapPage() { const originMarker = findBuildingMarker(origin.id); if (!originMarker) return; - originMarker.content = originMarkerContent({ title: origin.buildingName }); + originMarker.content = createMarkerElement({ + type: Markers.ORIGIN, + title: origin.buildingName, + className: "translate-routemarker", + }); return () => { - originMarker.content = buildingMarkerContent({ title: origin.buildingName }); + originMarker.content = createMarkerElement({ + type: Markers.BUILDING, + title: origin.buildingName, + className: "translate-routemarker", + }); }; }, [origin]); @@ -272,10 +256,18 @@ export default function MapPage() { const destinationMarker = findBuildingMarker(destination.id); if (!destinationMarker) return; - destinationMarker.content = destinationMarkerContent({ title: destination.buildingName }); + destinationMarker.content = createMarkerElement({ + type: Markers.DESTINATION, + title: destination.buildingName, + className: "translate-routemarker", + }); return () => { - destinationMarker.content = buildingMarkerContent({ title: destination.buildingName }); + destinationMarker.content = createMarkerElement({ + type: Markers.BUILDING, + title: destination.buildingName, + className: "translate-routemarker", + }); }; }, [destination]); diff --git a/uniro_frontend/src/pages/search.tsx b/uniro_frontend/src/pages/search.tsx index 89c3824..cc749d2 100644 --- a/uniro_frontend/src/pages/search.tsx +++ b/uniro_frontend/src/pages/search.tsx @@ -11,7 +11,7 @@ export default function UniversitySearchPage() { return (
    - { }} placeholder="우리 학교를 검색해보세요" handleVoiceInput={() => { }} /> + {}} placeholder="우리 학교를 검색해보세요" handleVoiceInput={() => {}} />
      void, +) { + const newMarker = new AdvancedMarker({ + map: map, + position: position, + content: content, + }); + + if (onClick) newMarker.addListener("click", onClick); + + return newMarker; +} From 039d64567de8a2957a2d54b5e9dfa92718350a85 Mon Sep 17 00:00:00 2001 From: dgfh0450 Date: Fri, 31 Jan 2025 18:14:04 +0900 Subject: [PATCH 15/16] =?UTF-8?q?[UNI-49]=20fix=20:=20Conflict=20=ED=95=B4?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- uniro_frontend/package-lock.json | 2 +- uniro_frontend/src/components/map/mapMarkers.tsx | 1 - uniro_frontend/src/index.css | 1 - uniro_frontend/src/pages/buildingSearch.tsx | 6 +++--- uniro_frontend/src/pages/demo.tsx | 14 +++++++------- uniro_frontend/src/pages/map.tsx | 9 ++++++--- 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/uniro_frontend/package-lock.json b/uniro_frontend/package-lock.json index 69b467c..2e6abb3 100644 --- a/uniro_frontend/package-lock.json +++ b/uniro_frontend/package-lock.json @@ -17,7 +17,7 @@ "react-router": "^7.1.3", "react-spring-bottom-sheet": "^3.4.1", "tailwindcss": "^4.0.0", - "zustand": "^5.0.3" + "zustand": "^5.0.3", "tailwindcss": "^4.0.0" }, "devDependencies": { diff --git a/uniro_frontend/src/components/map/mapMarkers.tsx b/uniro_frontend/src/components/map/mapMarkers.tsx index 9e4eaf9..dea1ee1 100644 --- a/uniro_frontend/src/components/map/mapMarkers.tsx +++ b/uniro_frontend/src/components/map/mapMarkers.tsx @@ -44,7 +44,6 @@ function createImageElement(type: MarkerTypes): HTMLElement { function createContainerElement(className?: string) { const container = document.createElement("div"); - console.log(className); container.className = `flex flex-col items-center space-y-[7px] ${className}`; return container; diff --git a/uniro_frontend/src/index.css b/uniro_frontend/src/index.css index e00daf2..3508d62 100644 --- a/uniro_frontend/src/index.css +++ b/uniro_frontend/src/index.css @@ -136,4 +136,3 @@ @utility translate-waypoint { transform: translateY(+4px); } - diff --git a/uniro_frontend/src/pages/buildingSearch.tsx b/uniro_frontend/src/pages/buildingSearch.tsx index aa297b4..5fb468a 100644 --- a/uniro_frontend/src/pages/buildingSearch.tsx +++ b/uniro_frontend/src/pages/buildingSearch.tsx @@ -1,5 +1,5 @@ import Input from "../components/customInput"; -import { buildings } from "../data/mock/hanyangBuildings"; +import { hanyangBuildings } from "../data/mock/hanyangBuildings"; import BuildingList from "../components/building/buildingList"; import useSearchBuilding from "../hooks/useSearchBuilding"; @@ -8,11 +8,11 @@ export default function BuildingSearchPage() { return (
      - {}} handleVoiceInput={() => {}} placeholder="" /> + { }} handleVoiceInput={() => { }} placeholder="" />
        - {buildings.map((building) => ( + {hanyangBuildings.map((building) => ( setBuilding(building)} key={`building-${building.buildingName}`} diff --git a/uniro_frontend/src/pages/demo.tsx b/uniro_frontend/src/pages/demo.tsx index 96dc804..d082b02 100644 --- a/uniro_frontend/src/pages/demo.tsx +++ b/uniro_frontend/src/pages/demo.tsx @@ -31,30 +31,30 @@ export default function Demo() {
        - {}} isActive={false} /> - {}} isActive={true} /> + { }} isActive={false} /> + { }} isActive={true} />
        - {}} isActive={false} /> - {}} isActive={true} /> + { }} isActive={false} /> + { }} isActive={true} />
        {}} + handleVoiceInput={() => { }} onLengthChange={(e: string) => { console.log(e); }} /> - {}} placeholder="출발지를 입력하세요"> + { }} placeholder="출발지를 입력하세요"> {}} + onClick={() => { }} placeholder="도착지를 입력하세요" value={destination} onCancel={() => setDestination("")} diff --git a/uniro_frontend/src/pages/map.tsx b/uniro_frontend/src/pages/map.tsx index 2cd7be4..f93ad44 100644 --- a/uniro_frontend/src/pages/map.tsx +++ b/uniro_frontend/src/pages/map.tsx @@ -1,6 +1,6 @@ import { useEffect, useRef, useState } from "react"; import useMap from "../hooks/useMap"; -import { buildings } from "../data/mock/hanyangBuildings"; +import { hanyangBuildings } from "../data/mock/hanyangBuildings"; import createMarkerElement from "../components/map/mapMarkers"; import { mockHazardEdges } from "../data/mock/hanyangHazardEdge"; import { BottomSheet, BottomSheetRef } from "react-spring-bottom-sheet"; @@ -50,7 +50,9 @@ export default function MapPage() { if (marker) { const { type, element } = marker; - element.content = createMarkerElement({ type }); + if (type === Markers.BUILDING) return undefined; + + element.content = createMarkerElement({ type, }); } return undefined; }); @@ -61,7 +63,7 @@ export default function MapPage() { if (AdvancedMarker === null || map === null) return; const markersWithId: { id: string; element: AdvancedMarker }[] = []; - for (const building of buildings) { + for (const building of hanyangBuildings) { const { id, lat, lng, buildingName } = building; const buildingMarker = createAdvancedMarker( @@ -187,6 +189,7 @@ export default function MapPage() { marker.content = createMarkerElement({ type: Markers.BUILDING, title: selectedMarker.property.buildingName, + className: "translate-marker", }); }; From 3f215eb884175e8496c85688fa1c343caf01693d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Junhyeok=20Park=28=EB=B0=95=EC=A4=80=ED=98=81=29?= Date: Fri, 31 Jan 2025 18:36:12 +0900 Subject: [PATCH 16/16] =?UTF-8?q?[UNI-49]=20fix=20:=20BuildingList=20->=20?= =?UTF-8?q?BuildingCard=EB=A1=9C=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../building/{buildingList.tsx => buildingCard.tsx} | 2 +- uniro_frontend/src/pages/buildingSearch.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename uniro_frontend/src/components/building/{buildingList.tsx => buildingCard.tsx} (94%) diff --git a/uniro_frontend/src/components/building/buildingList.tsx b/uniro_frontend/src/components/building/buildingCard.tsx similarity index 94% rename from uniro_frontend/src/components/building/buildingList.tsx rename to uniro_frontend/src/components/building/buildingCard.tsx index 805274d..fce088a 100644 --- a/uniro_frontend/src/components/building/buildingList.tsx +++ b/uniro_frontend/src/components/building/buildingCard.tsx @@ -8,7 +8,7 @@ interface BuildingListProps { onClick: () => void; } -export default function BuildingList({ building, onClick }: BuildingListProps) { +export default function BuildingCard({ building, onClick }: BuildingListProps) { const { buildingName, buildingImageUrl, address, phoneNumber } = building; return (
      • diff --git a/uniro_frontend/src/pages/buildingSearch.tsx b/uniro_frontend/src/pages/buildingSearch.tsx index 5fb468a..1fea395 100644 --- a/uniro_frontend/src/pages/buildingSearch.tsx +++ b/uniro_frontend/src/pages/buildingSearch.tsx @@ -1,6 +1,6 @@ import Input from "../components/customInput"; import { hanyangBuildings } from "../data/mock/hanyangBuildings"; -import BuildingList from "../components/building/buildingList"; +import BuildingCard from "../components/building/buildingCard"; import useSearchBuilding from "../hooks/useSearchBuilding"; export default function BuildingSearchPage() { @@ -13,7 +13,7 @@ export default function BuildingSearchPage() {
          {hanyangBuildings.map((building) => ( - setBuilding(building)} key={`building-${building.buildingName}`} building={building}