🌍

HexBin Map 구현 D3, React

Posted on Wed, Dec 23, 2020
2020-04-21 Total Cloud Cover 78 hour forecast visualized with H3, Leaflet.js and D3.

This was produced by taking the grid data from National Digital Forecast Database then processing to H3 indexes at various resolutions then visualizing via GeoJSON.

필요 개념 및 라이브러리

Leaflet

Leaflet은 모바일에 친화적인 상호작용 지도를 만들어 주는 자바스크립트 라이브러리다. react에는 React Leaflet이라는 라이브러리가 따로 있다.

react-leaflet의 경우 leaflet과는 별도의 라이브러리다. 따라서, 설치를 위해서는 기본적으로 react-leaflet과 leaflet을 모두 설치해야 한다.

yarn add react-leaflet leaflet
yarn add -D @types/react-leaflet

<link
  rel="stylesheet"
  href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
  integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
  crossOrigin=""
/>
<script
  src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
  integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
  crossOrigin=""
></script>

import styled from '@emotion/styled'
import { LatLngTuple } from 'leaflet'
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet'

const PageWrapper = styled.div`
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
`

interface PlayPageProps {}

function PlayPage({}: PlayPageProps) {
  const position: LatLngTuple = [51.505, -0.09]

  return (
    <PageWrapper>
      <MapContainer center={position} zoom={13} scrollWheelZoom={false}>
        <TileLayer
          attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
        <Marker position={position}>
          <Popup>
            A pretty CSS3 popup. <br /> Easily customizable.
          </Popup>
        </Marker>
      </MapContainer>
    </PageWrapper>
  )
}

export default PlayPage

이번 프로젝트에서는 개발 환경 자체가 Next로 개발된 SSR을 하고 있기 때문에 예제 코드를 실행할 경우 아래와 같은 에러가 발생한다.

Server Error
ReferenceError: window is not defined
This error happened while generating the page. Any console logs will be displayed in the terminal window.

이는 react-leaflet에서도 명시하고 있는 문제로 해결하기 위해서는 SSR이 아닌 CSR로 바꾸어 진행하려 한다.

Leaflet makes direct calls to the DOM when it is loaded, therefore React Leaflet is not compatible with server-side rendering.

이를 위해서는 Next.js의 Dynamic Import 기능을 이용하여 쉽게 해결할 수 있다.

import React from 'react'
import styled from '@emotion/styled'
import dynamic from 'next/dynamic'
import { isBrowser } from 'utils/index'

const NoSSRComponent = dynamic(() => import('components/Map'), {
  ssr: false,
})

const PageWrapper = styled.div`
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
`

interface PlayPageProps {}

function PlayPage({}: PlayPageProps) {
  return <PageWrapper>{isBrowser && <NoSSRComponent />}</PageWrapper>
}

export default PlayPage

import { css } from '@emotion/react'
import { LatLngTuple } from 'leaflet'
import { MapContainer, TileLayer } from 'react-leaflet'

function Map() {
  const position: LatLngTuple = [51.505, -0.09]
  return (
    <MapContainer
      center={position}
      zoom={5}
      scrollWheelZoom={false}
      css={css`
        width: 100%;
        height: 100%;
      `}
    >
      <TileLayer
        attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
        url="http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png"
      />
    </MapContainer>
  )
}

export default Map

Reference