분류 javascript

Gatsby 및 Leaflet과 React를 이용하여 코로나 바이러스 (COVID-19) 대시 보드 및 맵 앱을 생성하는 방법

컨텐츠 정보

  • 조회 657 (작성일 )

본문

How to create a Coronavirus (COVID-19) Dashboard & Map App in React with Gatsby and Leaflet 


코로나 바이러스 (COVID-19) 전염병은 우리 모두가 일상적으로 상호 작용하는 방식을 빠르게 변화 시켰습니다. 사용 가능한 API를 사용하여 전 세계에 미치는 영향을 보여주는 매핑 앱을 어떻게 만들 수 있습니까?


https://www.freecodecamp.org/news/how-to-create-a-coronavirus-covid-19-dashboard-map-app-in-react-with-gatsby-and-leaflet/ 


작성자 참고 사항 : 이것은 실제 데이터를 사용하여 효과적인 매핑 응용 프로그램을 구성하기 위한 데모 및 개념 증명을 위한 것입니다. 완벽하고 정확한 분석을 위해서는 Johns Hopkins University 대시 보드와 같은 도구를 사용해야 합니다. 집에 있어 안전 하십시오! ❤️



우리는 무엇을 만들 것입니까? 


최신 코로나 바이러스 통계가 포함 된 API를 사용하고 각 국가가 직면하고 있는 위치와 영향을 매핑 하는 매핑 응용 프로그램을 만들 것입니다.


coronavirus-map-dashboard-demo.jpg 

코로나 바이러스 맵 대시 보드 데모



지도에는 확인 된 사례 수와 함께 각 국가의 마커가 표시됩니다. 그 외에도 더 자세한 정보를 보여주는 작은 팝업 툴팁이 포함됩니다.


우리가 만들 지도는 대부분 위와 비슷하지만 조금 더 단순 해 보일 것입니다. 맞춤지도 상자를 사용하는 대신 OpenStreetMap 공개 타일 서버를 사용합니다


시작하기 위해, 우리는 초기 설정을 좀 더 부드럽게 하기 위해 만든 이 Leaflet Gatsby Starter를 사용할 것입니다. 앱이 부트스트랩 되면 데이터를 가져 와서 데이터가 포함 된 마커를 지도에 추가합니다.


와, 매핑 앱? 


예. 전에 지도를 가지고 놀지 않았다면 낙심 하지 마십시오! 생각만큼 나쁘지 않습니다. 매핑 기본 사항부터 시작하려면 먼저 매핑 작동 방식에 대해 자세히 알아볼 수 있습니다.


시작하기 전에 무엇이 필요합니까? 


산타 트래커를 작성하거나 여름 로드 트립 맵을 작성하기 위한 이전 학습서와 함께 수행 한 경우 동일한 단계를 수행하여 시작할 수 있습니다. 그렇지 않은 경우 다음을 설정해야 합니다.

  • node or yarn - yarn를 사용하지만 적절한 경우 npm으로 대체 할 수 있습니다
  • Gatsby’s CLI - yarn global add gatsby-cli


위 중 하나에 대해 잘 모르겠으면 이전 자습서의 시작 부분을 확인하십시오.


또한 지도의 토대를 마련하고자 합니다. 우리는 Leaflet Gatsby Starter를 활용하여 Leaflet과 React Leaflet의 기본 설정을 제공함으로써 이를 수행 할 수 있습니다.


gatsby new my-coronavirus-map https://github.com/colbyfayock/gatsby-starter-leaflet

terminal-creating-new-coronavirus-map-from-gatsby-starter.jpg 

터미널에서 새로운 Leaflet Gatsby 앱 만들기


실행이 끝나면 새로 만든 프로젝트 디렉토리로 이동하여 로컬 개발 서버를 시작할 수 있습니다.


cd my-coronavirus-map
yarn develop

terminal-starting-gatsby-development-server-1.jpg 

터미널에서 Gatsby 앱 시작



모든 것이 계획대로 진행되면 서버가 시작되고 이제 브라우저에서 기본 매핑 앱을 볼 수 있습니다!


gatsby-starter-leaflet-in-browser-1.jpg 

브라우저의 새로운 Leaflet Gatsby 앱


1 단계 : 불필요한 코드 정리 


이 앱을 시작하는 데 사용하는 Gatsby Starter에는 여기에 필요하지 않은 데모 코드가 있습니다. 앱의 홈페이지 인 src/pages/index.js 파일에서 아래의 모든 사항을 변경하려고 합니다.


먼저 mapEffect 함수에서 모든 것을 제거해 봅시다. 이 함수는 지도가 렌더링 될 때 발생하는 코드를 실행하는 데 사용됩니다.


// In src/pages/index.js
async function mapEffect({ leafletElement } = {}) {
  // Get rid of everything in here
}

코드를 작성할 때 코드를 더 쉽게 이해할 수 있도록 leafletElement의 변수 이름도 변경합니다.

async function mapEffect({ leafletElement: map } = {}) {
}

다음으로 이번에는 마커를 원하지 않으므로 <Map 구성 요소에서 <Marker 구성 요소를 제거하겠습니다.


<Map {…mapSettings} />

이제 그 조각들을 정리 했으므로 파일 맨 위에서 다음의 모든 가져 오기 및 변수를 제거 할 수 있습니다.

  • useRef
  • Marker
  • promiseToFlyTo
  • getCurrentLocation
  • gatsby_astronaut
  • timeToZoom
  • timeToOpenPopupAfterZoom
  • timeToUpdatePopupAfterZoom
  • ZOOM
  • popupContentHello
  • popupContentGatsby
  • markerRef

이후에도 지도는 여전히 작동하지만 아무 것도 하지 않아야 합니다.

new-empty-mapping-app-1.jpg 

아무 일도 일어나지 않는 새로운 매핑 앱


2 단계 : 코로나 바이러스 데이터 가져 오기 


우리 앱에는 NovelCOVID API를 사용할 것입니다. 특히, 국가 엔드 포인트를 사용하여 국가 목록과 관련 통계를 가져옵니다.


요청을 할 때 API를 사용하기 좋은 axios를 개인적으로 사용하고 싶습니다. fetch 또는 선호하는 요청 라이브러리를 사용하려면 이 단계를 대신 사용하십시오.


우리는 다음과 같이 axios를 설치합니다 :


yarn add axios

설치가 완료되면 서버를 다시 시작해야 합니다.


pages / index.js 파일 상단에서 axios 패키지를 가져옵니다.

import axios from ‘axios’;

다음으로 실제로 요청합니다. mapEffect 함수 내에서 API 엔드 포인트에 요청을 하겠습니다.

async function mapEffect({ leafletElement: map } = {}) {
    let response;

    try {
      response = await axios.get(‘https://corona.lmao.ninja/countries’);
    } catch(e) {
      console.log(`Failed to fetch countries: ${e.message}`, e);
      return;
    }

    const { data = [] } = response;
}

이 스니펫에서는 다음을 수행합니다.

  • 응답을 저장할 수 있는 응답 변수 설정
  • 요청이 실패하면 API 오류를 포착하는 try / catch 블록 추가
  • 요청이 성공하면 응답을 응답 변수에 저장합니다
  • 요청이 실패하면 오류를 콘솔 로그 아웃하고 함수에서 반환하므로 실패한 요청으로 코드를 계속 실행하지 않습니다.
  • 응답이 있으면 응답에서 데이터를 구조 해제하고 기본값을 빈 배열로 설정할 수 있습니다. 이것이 필요한 데이터 유형이기 때문입니다.


설정이 완료되면 콘솔에서 데이터 객체를 로그아웃하면 데이터를 성공적으로 가져 왔습니다.

coronavirus-location-data-in-browser.jpg 

브라우저 콘솔에 Coronavirus 위치 데이터 로깅


3 단계 : 코로나 바이러스 데이터를 지리적 데이터 형식으로 변환 


이제 데이터가 확보되었으므로, 데이터를 지리적 데이터 형식, 특히 GeoJSON으로 변환하여 Leaflet과 인터페이스 할 수 있습니다.


이 코드 블록을 추가하여 시작하겠습니다.


const  { data  data =  []  }  = response response;

const hasData  hasData = Array Array.isArray(datadata)  && data data.length length >  0;



if  (  !hasData hasData )  return;



const geoJson  geoJson =  {
  type
  type: ‘FeatureCollection’ ‘FeatureCollection’,
  features
  features: data data.map((country = {})  =>  {
    
    const  { countryInfo  countryInfo =  {}  }  = country country;
    
    const  { lat lat, long long: lng  lng }  = countryInfo countryInfo;
    
    return  {
      type
      type: ‘Feature’ ‘Feature’,
      properties
      properties:  {
        …country
        …country,
      
      },
      geometry
      geometry:  {
        type
        type: ‘Point’ ‘Point’,
        coordinates
        coordinates:  [ lng lng, lat  lat ]
      
      }
    
    }
  
  })

}



우리 여기서 뭐하는 거야?


  • 데이터 변수가 배열이고 데이터가 있는지 확인하는 hasData라는 새로운 상수를 만듭니다.
  • 데이터가 없으면 가지고 있지 않은 데이터를 추가하려고 하지 않기 때문에 함수에서 복귀하려고 합니다.
  • GeoJSON 문서가 될 geoJson 객체를 만듭니다.
  • 우리의 문서는 FeatureCollection 유형이며 우리의 기능으로서 데이터 셋을 반복합니다.
  • 데이터의 각 국가에 대해 위도 및 경도를 구하여 지도에 대한 포인트를 만듭니다.
  • 또한 국가 데이터를 속성으로 추가하여 매핑 API 내에서 액세스 할 수 있습니다

이 객체를 브라우저에 console.log하고 내용을 복사하면 geojson.io에 붙여 넣고 위치 데이터가 올바르게 표시되는지 확인할 수 있습니다.

location-data-geojson-io.jpg 

geojson.io에서 코로나 바이러스 위치 데이터 미리보기


이 GeoJSON 문서를 사용하여 이제 지도에 추가 할 수 있습니다.


4 단계 :지도에 코로나 바이러스 데이터 추가 


위치 데이터가 포함 된 GeoJSON 문서가 있으므로 지도에 추가하겠습니다.


이 코드 블록부터 시작하겠습니다. 긴 것이지만, 우리는 그것을 하나씩 분해 할 것입니다 :

const geoJsonLayers = new L.GeoJSON(geoJson, {
  pointToLayer: (feature = {}, latlng) => {
    const { properties = {} } = feature;
    let updatedFormatted;
    let casesString;

    const {
      country,
      updated,
      cases,
      deaths,
      recovered
    } = properties

    casesString = `${cases}`;

    if ( cases > 1000 ) {
      casesString = `${casesString.slice(0, -3)}k+`
    }

    if ( updated ) {
      updatedFormatted = new Date(updated).toLocaleString();
    }

    const html = `
      <span class=“icon-marker”>
        <span class=“icon-marker-tooltip”>
          <h2>${country}</h2>
          <ul>
            <li><strong>Confirmed:</strong> ${cases}</li>
            <li><strong>Deaths:</strong> ${deaths}</li>
            <li><strong>Recovered:</strong> ${recovered}</li>
            <li><strong>Last Update:</strong> ${updatedFormatted}</li>
          </ul>
        </span>
        ${ casesString }
      </span>
    `;

    return L.marker( latlng, {
      icon: L.divIcon({
        className: ‘icon’,
        html
      }),
      riseOnHover: true
    });
  }
});

우리 여기서 뭐하는 거야?


  • 우리는 GeoJSON 문서를 Leaflet이 이해할 수 있는 것으로 바꿀 L.GeoJSON의 새로운 인스턴스를 만듭니다.
  • 해당 인스턴스 내에서 사용자 정의 pointToLayer 함수를 정의합니다. 이를 통해 Leaflet이 지도에 생성하는지도 레이어를 사용자 정의 할 수 있습니다.
  • 함수에서 원하는 데이터 포인트를 할당하고 만듭니다. 대부분 파괴적이지만 케이스 수를 1000 대신 1k +로 표시하고 타임 스탬프 대신 형식화 된 날짜로 표시합니다.
  • 지도에 추가 될지도 표시자를 정의하는 데 사용되는 HTML 문자열 블록을 만듭니다. 여기에는 마커 위에 마우스를 올릴 때 표시되는 툴팁의 HTML도 포함됩니다.
  • 컨테이너 및 사용자 정의 HTML 아이콘 클래스를 포함하는 사용자 정의 구성으로 L.marker를 리턴합니다.
  • 또한 riseOnHover 속성을 추가하여 마커 위로 마우스를 가져 가면 지도의 다른 마커 위에 표시됩니다.


또한 마커를 지도에 표시하고 사용할 수 있도록 여기에 약간의 CSS를 추가하려고 합니다. 이 스니펫을 asset/stylesheets/components/_map.scss 파일에 추가하겠습니다 :

.icon-marker {

  display: flex;
  position: relative;
  justify-content: center;
  align-items: center;
  color: white;
  width: 3.6em;
  height: 3.6em;
  font-size: .7em;
  font-weight: bold;
  background-color: $red-800;
  border-radius: 100%;
  box-shadow: 0 2px 5px rgba(black, .9);

  &:hover {

    .icon-marker-tooltip {
      display: block;
    }

  }

}

.icon-marker-tooltip {

  display: none;
  position: absolute;
  bottom: 100%;
  width: 16em;
  font-size: 1.4em;
  padding: 1em;
  background-color: $blue-grey-900;
  border-radius: .4em;
  margin-bottom: 1em;
  box-shadow: 0 3px 5px rgba(black, .9);

  &:before {
    display: block;
    position: absolute;
    bottom: -.6em;
    left: 50%;
    content: ‘’;
    width: 1.4em;
    height: 1.4em;
    background-color: $blue-grey-900;
    transform: rotate(45deg);
    margin-left: -.7em;
  }

  h2 {
    font-size: 1.5em;
    line-height: 1.2;
    margin-bottom: .1em;
    margin-top: 0;
  }

  h3 {
    font-size: 1.2em;
    margin: .1em 0;
    font-weight: normal;
    color: $blue-grey-100;
  }

  ul,
  p {
    font-weight: normal;
  }

  ul {
    list-style: none;
    padding: 0;
    margin: .6em 0 0;
  }

}

우리가 하고 있는 일 :


  • .icon-marker 클래스를 사용하여 라운드 마커를 만들고 .icon-marker-tooltip 클래스를 설정하여 마우스를 올려 놓으면 표시됩니다.
  • .icon-marker-tooltip 클래스는 툴팁이므로 기본적으로 숨겨져 있지만 마커 위에 표시되도록 원하는 위치에 배치하고 원하는 방식으로 형식을 지정합니다.


마지막으로 스타일을 추가하여 geoJsonLayers를 만들면 맵에 추가 할 수 있습니다!


geoJsonLayers.addTo(map)

map-with-coronavirus-location-data.jpg 

코로나 바이러스 위치 데이터가 포함 된 지도


이제 왜 그것이 제대로 중앙에 나타나지 않는지 궁금 할 것입니다. 계속해서 index.js 파일의 맨 위에 있는 LOCATION 변수를 다음과 같이 변경하십시오.


const LOCATION = {
  lat: 0,
  lng: 0
};

설정이 완료되면 페이지가 새로 고침 될 때 지도가 세계 중앙에 위치해야 합니다.

map-with-coronavirus-location-data-centered-tooltip.jpg 

툴팁을 중심으로 코로나 바이러스 위치 데이터로 매핑


예, 우리는 해냈습니다! ? 


따라 한 경우 이제 전 세계 사례에 대한 간단한 통계를 제공하는 고유 한 코로나 바이러스 맵 대시 보드를 만들었습니다.


배운 것을 가지고 그것을 실행하십시오. 상상할 수 있는 다른 유형의 데이터에 적용 할 수 있습니다.


우리는 무엇을 더 할 수 있습니까? 


더 많은 스타일과 커스텀베이스 맵 추가 


원래 데모에서는 Mapbox를 사용하여 마커를 보다 쉽게 ​​볼 수 있도록 어두운 배경을 가질 수 있는 사용자 정의베이스 맵을 설정했습니다.

mapbox-studio-basemap.jpg 

Mapbox Studio에서 새로운베이스 맵 생성


Mapbox는 훌륭하고 시작에 관심이 있다면 멋진 프리 티어가 있습니다.


Mapbox 계정이 있으면 내가 사용한 스타일을 복사하여 자신 만의 스타일로 만들 수도 있습니다.


기본 다크 맵 박스 테마


통합 방법을 배우려면 원래 데모의 소스 코드를 확인하십시오.


https://github.com/colbyfayock/coronavirus-map-dashboard


개요 대시 보드 통계 추가 


Johns Hopkins University 앱과 같은 지도가 포함 된 대시 보드를 사용하면 지도를 보는 것 이상을 볼 수 있지만 전 세계 사례에 대한 빠른 통계를 엿볼 수 있습니다.


johns-hopkins-coronavirus-map-march-29.jpg 

Johns Hopkins University Coronavirus지도 대시 보드-2020 년 3 월 29 일


NovelCOVID API에는 / all과 같은 글로벌 통계를 제공하는 더 많은 엔드 포인트가 있습니다.


안전하고 정보를 유지하십시오 


Johns Hopkins University 대시 보드와 같은 공식 정보 소스를 사용하여 최신 상태를 유지해야 합니다. 데이터는 신뢰할 수 있어야 하지만 지도 작성 및 참조를 위한 개념 증명으로 간주되어야 하지만 모든 종류의 통계 분석에는 고려해서는 안됩니다.


이 시간 동안 몸조심하십시오. 우리는 모두 함께 있습니다! ❤️


지도에 대해 더 자세히 알고 싶으십니까? 


시작하기 위해 다른 리소스를 확인하십시오.