๐Ÿ“react-map-gl, Mapbox๋ฅผ ํ™œ์šฉํ•œ ์ง€๋„๐Ÿ—บ ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ - React ํ”„๋ก ํŠธ ํŽธ๐Ÿš‚

2021. 7. 23. 12:51ใ†๐Ÿ’™ React

1.  React ์„ค์น˜

ํ”„๋ก ํŠธ์•ค๋“œ ํด๋”๋กœ ์ด๋™ํ•ด ํ˜„์žฌ ํด๋” ๋‚ด๋ถ€(.)์— react๋ฅผ ์„ค์น˜ํ•œ๋‹ค.

 

cd frontend

npx create-react-app . 

 

|  2.  ํฐํŠธ ์„ ํƒ

fonts.google.com

๋ฆฌ์•กํŠธ ์„ค์น˜๊ฐ€ ์ง„ํ–‰๋˜๋Š” ๋™์•ˆ ๊ตฌ๊ธ€ ํฐํŠธ.com์— ์ ‘์†ํ•˜์—ฌ ํ”„๋กœ์ ํŠธ์— ์‚ฌ์šฉ๋  ํฐํŠธ๋ฅผ ๊ณจ๋ผ ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ๋ณต์‚ฌํ•œ๋‹ค.

[ ๋ณต์‚ฌํ•œ ์ฝ”๋“œ ]

// link ์ฝ”๋“œ
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,500;0,600;0,700;0,900;1,400;1,900&display=swap" rel="stylesheet">

// css ์ฝ”๋“œ
font-family: 'Playfair Display', serif;

 

ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ํ”„๋ก ํŠธ์˜ publicํด๋”  > index.html ํŒŒ์ผ ๋‚ด๋ถ€์— ๋ถ™์—ฌ์ฃผ๋ฉด ํ”„๋กœ์ ํŠธ ์† ๊ธ€๊ผด ์ง€์ •์ด ์™„๋ฃŒ๋œ๋‹ค.

index.html์— ์ž‘์„ฑํ•  css ์Šคํƒ€์ผ ์ฝ”๋“œ๊ฐ€ 2~3์ค„๋กœ ์งง๊ธฐ ๋•Œ๋ฌธ์— ๋ณ„๋„์˜ css ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  html ๋ฌธ์„œ ๋‚ด๋ถ€์— style ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ์ค€๋‹ค. ( ์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด์ง€๊ฒŒ ๋œ๋‹ค๋ฉด css ํŒŒ์ผ ์ƒ์„ฑ์„ ํ•„์ˆ˜! )

์šฐ์„  ๊ธ€๊ผด ์ง€์ • ์ „, ์„ค์น˜๋œ ๋ฆฌ์•กํŠธ ํŒŒ์ผ ์† ๋ถˆํ•„์š”ํ•œ ํŒŒ์ผ๊ณผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ฝ”๋“œ๋ฅผ ์ •๋ฆฌํ•˜๋Š” ์ž‘์—…์„ ์ง„ํ–‰ํ•œ๋‹ค.

 


|  3. React ํด๋” ์ตœ์ ํ™” ์ž‘์—… - ๋ถˆํ•„์š” ํŒŒ์ผ ๋ฐ ์ฝ”๋“œ ์ œ๊ฑฐ

ํ•„์ˆ˜ ํŒŒ์ผ๋งŒ ๋‚จ๊ฒจ๋†“์€ front ํด๋” ๋ชจ์Šต

1 ) public ํด๋”
> index.html๋ฅผ ์ œ์™ธํ•œ ํŒŒ์ผ์„ ๋ชจ๋‘ ์ œ๊ฑฐํ•˜๊ณ , index.html ํŒŒ์ผ ์† ๋ถˆํ•„์š”ํ•œ ์ฝ”๋“œ๋ฅผ ์ •๋ฆฌํ•œ๋‹ค.

  • index.html
    ์ฃผ์„ ๋ฐ ๋ถˆํ•„์š”ํ•œ ์ฝ”๋“œ๋Š” ์ œ๊ฑฐํ•˜๊ณ , ํ”„๋กœ์ ํŠธ์— ๋งž๋Š” <title>์„ ์ž‘์„ฑํ•ด์ค€๋‹ค.
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <title>Travel Map</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
  • ๊ธ€๊ผด ์ง€์ •์„ ์œ„ํ•ด html ๋‚ด๋ถ€์— ์ž‘์„ฑํ•œ๋‹ค.
    <link href="https://fonts.googleapis.com/css2?family=Zen+Loop&display=swap" rel="stylesheet">
    <style>
      *{
        font-family: 'Zen Loop', cursive;
        margin :0;
      }
    </style>

 

2 ) src ํด๋”

> App.js ์™€ index.js ๋งŒ ๋‚จ๊ฒจ๋‘๊ณ  ํŒŒ์ผ ์ œ๊ฑฐํ•œ๋‹ค.

  • App.js  - ํŒŒ์ผ ์† css import์™€ ๊ฐ™์€ ๋ถˆํ•„์š”ํ•œ ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค.
function App() {
  return (
    <div> Travel Map</div>
  );
}

export default App;

 

  • index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

 

yarn start ๋ฅผ ํ†ตํ•ด ๊ธ€๊ผด ์ ์šฉ๋œ ํ”„๋กœ์ ํŠธ๊ฐ€ ์ •์ƒ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค ๐Ÿ’™


 

|  4. Mapbox์— ์ ‘์†ํ•ด ์ง€๋„ ์‚ฌ์šฉ์„ ์œ„ํ•œ ํ† ํฐ ํ‚ค๋ฅผ ๋ฐ›์•„์˜จ๋‹ค.

 

Maps, geocoding, and navigation APIs & SDKs | Mapbox

Integrate custom live maps, location search, and turn-by-turn navigation into any mobile or web app with Mapbox APIs & SDKs. Get started for free.

www.mapbox.com

์œ„ ์‚ฌ์ดํŠธ์— ์ ‘์†ํ•ด navbar ์ƒ๋‹จ์˜ Products > Maps๋ฅผ ํ…์— ์ ‘์†ํ•˜๋ฉด ํ€„๋ฆฌํ‹ฐ ์ข‹์€ ๋‹ค์–‘ํ•œ ์ง€๋„ ํ™”๋ฉด์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์šฐ์„  ํšŒ์›๊ฐ€์ž… ํ›„ ์ž์‹ ์˜ Account ํŽ˜์ด์ง€๋กœ ์ ‘์†ํ•˜๋ฉด ํ•˜๋‹จ์— ํ”„๋กœ์ ํŠธ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” token ํ‚ค๊ฐ€ ์ฃผ์–ด์ง‘๋‹ˆ๋‹ค ๐Ÿˆ

ํ•ด๋‹น token ๊ฐ’์„ ๋ณต์‚ฌํ•˜์—ฌ front ์† .env ํŒŒ์ผ์„ ์ƒ์„ฑํ•ด ์ €์žฅํ•ด์ค๋‹ˆ๋‹ค.

REACT ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์† ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋Š” ๋ณ€์ˆ˜๋ช… ์•ž์— REACT_APP_ ๋ฅผ ์ถ”๊ฐ€ํ•ด ์ž‘์„ฑํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

REACT_APP_MAP_TOKEN = Mapbox ํ† ํฐ๊ฐ’

 

 

 

|  5.  react-map-gl ์„ค์น˜ ๋ฐ ํ† ํฐํ‚ค ์—ฐ๊ฒฐ

์ด์ œ ๋ฐ›์•„์˜จ ํ† ํฐํ‚ค๋ฅผ ํ™œ์šฉํ•ด ๋‹ค์–‘ํ•œ ์ง€๋„๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณธ๊ฒฉ ์…‹ํŒ…ํ•˜๋Ÿฌ ์ถœ๋ฐœ~ ๐Ÿ›ฐ

 

4-1) 'react-map-gl' ๋งต ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ด์ค๋‹ˆ๋‹ค.

yarn add react-map-gl

 

 

Vis.gl

Frameworks for WebGL-powered large-scale data visualization - Vis.gl

github.com

์„ค์น˜ ์ง„ํ–‰๋˜๋Š” ๋™์•ˆ ์œ„ Document ์‚ฌ์ดํŠธ์— ์ ‘์†ํ•ด get staeted๋ฅผ ํด๋ฆญํ•˜๋ฉด ์ฝ”๋“œ ์ž‘์„ฑ์— ํ•„์š”ํ•œ ๋‹ค์–‘ํ•œ ๋ฌธ์„œ๋“ค์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

import ๋ฅผ ํ†ตํ•ด ํ”„๋กœ์ ํŠธ ์ฝ”๋“œ ๋‚ด๋ถ€์—์„œ ๋งต ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, userState hook ๋‚ด๋ถ€์— ๋„ˆ๋น„, ๋†’์ด ๋“ฑ์— ๊ด€ํ•œ ์ฝ”๋“œ๊ฐ€ ์ž‘์„ฑ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค. ์œ„ ์ฝ”๋“œ๋ฅผ ํ† ๋Œ€๋กœ App.js๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•œ๋‹ค.

import { useState } from 'react';
import ReactMapGL from 'react-map-gl';

function App() {
  const [viewport, setViewport] = useState({
    width: 400,
    height: 400,
    latitude: 37.7577,
    longitude: -122.4376,
    zoom: 8
  });
  
  return (
    <div>
      <ReactMapGL
        {...viewport}
        mapboxApiAccessToken = {process.env.REACT_APP_MAP_TOKEN} // mapboxApiAccessToken ๋ณ€์ˆ˜์— ํ† ํฐ๊ฐ’์„ ์ „๋‹ฌํ•ด์ค๋‹ˆ๋‹ค.
        onViewportChange={nextViewport => setViewport(nextViewport)}
      />
    </div>
  );
}

export default App;

<ReactMapGL> ํƒœ๊ทธ ์‚ฌ์ด mapboxApiAccessToken ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด localhost:3000์— ๋‹ค์Œํ™”๋ฉด์ด ์ •์ƒ ์ž‘๋™๋œ๋‹ค.

๋งต์„ ์—ฐ๊ฒฐํ•œ react ์‹คํ–‰ ๊ฒฐ๊ณผ

์‹คํ–‰ํ™”๋ฉด์ด ๋œจ์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ข…๋ฃŒ ํ›„ yarn start๋ฅผ ํ†ตํ•ด ๋ฆฌ์•กํŠธ๋ฅผ ์žฌ์‹คํ–‰ ์‹œ์ผœ์ค€๋‹ค.

 

์ง€๋„๋ฅผ ์ „์ฒด ํ™”๋ฉด์œผ๋กœ ํ‘œํ˜„ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด useState ์† width: "100vw"์™€  height: "100vh" ๋กœ ์กฐ์ ˆํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

 

 

๋˜ํ•œ ํ˜„์žฌ ์œ„์น˜ ์ƒŒํ”„๋ž€์‹œ์Šค์—์„œ ์›ํ•˜๋Š” ์œ„๋„ ๊ฒฝ๋„ ์ˆ˜์ •์„ ํ†ตํ•ด ์žฅ์†Œ๋ฅผ ๋ณ€๊ฒฝ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

์œ„๋„ ๊ฒฝ๋„ ๊ฐ’์„ ์„œ์šธ ๋ถ€๊ทผ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ , ํ™•๋Œ€๋œ ํฌ๊ธฐ๋ฅผ ์ค„์ด๊ณ  ์‹ถ์œผ๋ฉด zoom ๋ณ€์ˆ˜์˜ ์ˆซ์ž๋ฅผ ๋‚ฎ์ถฐ์ฃผ๋ฉด ๋œ๋‹ค.

์œ„๋„ ๊ฒฝ๋„๋ฅผ ์„œ์šธ๋กœ ์ˆ˜์ •ํ•œ ์ง€๋„ ๋ชจ์Šต
zoom ์ˆ˜์น˜๋ฅผ 8์—์„œ 4 ๋กœ ์กฐ์ ˆํ•œ ์ง€๋„ ํ™”๋ฉด

const [viewport, setViewport] = useState({
    width: "100vw", 	 // ์ง€๋„ ๋„ˆ๋น„
    height: "100vh", 	 // ๋†’์ด
    latitude: 37.562003, // ๊ฒฝ๋„
    longitude: 127, 	 // ์œ„๋„
    zoom: 4 		 // ํ™•๋Œ€ ์ˆ˜์น˜ ๐Ÿ’™
  });

 

|  6. ๋งต ์œ„์— Marker ํ‘œ๊ธฐ ์ฝ”๋“œ ์ž‘์„ฑ

API Reference > Marker ๋ฌธ์„œ๋ฅผ ํ™œ์šฉํ•ด ์ง€๋„ ์œ„์— Marker๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

 

react-map-gl | Marker

React wrapper for Mapbox GL JS

visgl.github.io

'react-map-gl' ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋ถ€ํ„ฐ Marker๋ฅผ import ํ•œ ๋‹ค์Œ <ReactMapGL> ํƒœ๊ทธ ๋‚ด๋ถ€์— Marker ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์ค€๋‹ค.

๋กฏ๋ฐํƒ€์›Œ์˜ ์œ„๋„ ๊ฒฝ๋„ ์œ„์น˜์— Marker๋ฅผ ํ‘œ์‹œํ•ด ๋ณด๊นŒ์œ ?

[ ์ถ”๊ฐ€๋œ ์ฝ”๋“œ ]

import { Marker } from 'react-map-gl';

<Marker latitude={37.5125} longitude={127.102778} offsetLeft={-20} offsetTop={-10}>
    <h1> Lotte Towel is here </h1>
</Marker>

[ ์ „์ฒด index.js ์ฝ”๋“œ ]

import { useState } from 'react';
import ReactMapGL, { Marker } from 'react-map-gl';

function App() {
  const [viewport, setViewport] = useState({
    width: "100vw",
    height: "100vh",
    latitude: 37.562003,
    longitude: 127,
    zoom: 8
  });
  return (
    <div>
      <ReactMapGL
        {...viewport}
        mapboxApiAccessToken={process.env.REACT_APP_MAP_TOKEN}
        onViewportChange={nextViewport => setViewport(nextViewport)}
      >
        <Marker latitude={37.5125} longitude={127.102778} offsetLeft={-20} offsetTop={-10}>
          <h1>Lotte Towel is here</h1>
        </Marker>
      </ReactMapGL>
    </div>
  );
}

export default App;

 

๋กฏ๋ฐ ํƒ€์›Œ ์œ„์น˜์— ํ‘œ์‹œ๋œ ๋งˆ์ปค

์ด์ œ css๋ฅผ ํ™œ์šฉํ•ด ๋งˆ์ปค๋ฅผ ์ด์˜๊ฒŒ ๊พธ๋ฉฐ์ฃผ๋„๋ก ํ•œ๋‹ค.

yarn add @material-ui/core @material-ui/icons
 

Material Icons - Material-UI

1,100+ React Material icons ready to use from the official website.

material-ui.com

material-icons๋กœ๋ถ€ํ„ฐ ์œ„ ์•„์ด์ฝ˜์„ importํ•ด์™€ <Marker> ํƒœ๊ทธ ์‚ฌ์ด์— ์ž‘์„ฑํ•ด์ค€๋‹ค.

import { Room } from '@material-ui/icons' ;

<Marker> <Room> <Marker/>

;

๋กฏ๋ฐ ํƒ€์›Œ ์œ„์น˜์— ํ•€ ์•„์ด์ฝ˜์œผ๋กœ ํ‘œ์‹œ๋œ ํ™”๋ฉด

 

์ด๋•Œ ์ง€๋„๋ฅผ ํ™•๋Œ€ํ• ๊ฒฝ์šฐ ์œ„์น˜๊ฐ€ ๊ณ ์ •๋œ์ฑ„ ์›ํ•˜๋Š” ์œ„์น˜๋กœ ์ด๋™๋˜์ง€ ์•Š๋Š”๋ฐ, ์•„์ด์ฝ˜์˜ fontsize๋ฅผ viewport.zoom * 5๋กœ ์ง€์ •ํ•ด์ฃผ๋ฉด ์ง€๋„ ์‚ฌ์ด์ฆˆ์— ๋งž๋Š” ์ ๋‹นํ•œ ํฌ๊ธฐ๋กœ ์ž˜ ๋ณ€๋™๋˜๋Š”๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

<Marker latitude={37.5125} longitude={127.102778} offsetLeft={-20} offsetTop={-10}>
      <Room style={{ fontSize: viewport.zoom * 5, color: "slateblue" }} />
</Marker>

 

|  7. ์ง€๋„ ๋””์ž์ธ ๋ณ€๊ฒฝ

 

Gallery

Browse our collection of maps to see what's possible with Studio

www.mapbox.com

๋‹ค์–‘ํ•œ ์ง€๋„ ํ˜•ํƒœ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค

 

๋‹ค์‹œ Mapbox์˜ account ํŽ˜์ด์ง€๋กœ ์ ‘์†ํ•ด Mapbox ์ŠคํŠœ๋””์˜ค ๋””์ž์ธ์„ ํด๋ฆญํ•œ๋‹ค

Design in Mapbox Studio ํ…์— ์ ‘์†ํ•ด New styles๋ฅผ ํด๋ฆญํ•œ๋‹ค.
๊ธฐํ˜ธ์— ๋งž๋Š” ๋””์ž์ธ์„ ์„ ํƒ ํ›„ ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ์ ‘์†ํ•˜๋ฉด
๋นŒ๋”ฉ, ๋„๋กœ ๋“ฑ ๊ฐœ๋ฐœ์ž ๊ธฐํ˜ธ์— ๋งž๋Š” ๋‹ค์–‘ํ•œ ์ƒ์„ธ ์ปค์ฆˆํ„ฐ์ฆ˜์ด ๊ฐ€๋Šฅํ•˜๋‹ค!

 

์ทจํ–ฅ์— ๋งž๊ฒŒ ์ง€๋„ ๋””์ž์ธ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•์„ ์™„๋ฃŒํ–ˆ๋‹ค๋ฉด ๋‹ค์‹œ styles๋กœ ๋Œ์•„์™€ ํ•ด๋‹น ์ง€๋„์˜ Style URL์„ ๋ณต์‚ฌํ•ด <ReactMapGL> ํƒœ๊ทธ ์†์˜ mapStyle๋กœ ์ž‘์„ฑํ•ด์ค€๋‹ค.

<ReactMapGL
        {...viewport}
        mapboxApiAccessToken={process.env.REACT_APP_MAP_TOKEN}
        onViewportChange={nextViewport => setViewport(nextViewport)}
        // ์ž์‹ ์ด ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•œ ์Šคํƒ€์ผ url ์‚ฝ์ž…
        mapStyle = "mapbox://styles/angluvpeng/ckrfpsp1f4o3417mxdnu564cw"
 >

๋””์ž์ธ ๋ณ€๊ฒฝ ์ „
๋””์ž์ธ์ด ์ ์šฉ๋œ ์ง€๋„! 

 

|  8. ์ง€๋„ ํ•€์— ํŒ์—…์ฐฝ ์„ค์ •

react-map-gl ๋ฌธ์„œ์— Popup ์ฝ”๋“œ
popUp ์ฐฝ ์ ์šฉ ๋ฐ css ์Šคํƒ€์ผ ์…‹ํŒ… ๊ฒฐ

 

 

Posted by Ang