React Native에서 세계 지도 보기

소개



직장에서 React Native를 사용해 개발을 하고 있어, 지견이 모여 왔습니다만, 기사에 일으키려고 고민하고 있는 사이에 꽤 지나 버렸습니다.

이번에는 화면에 세계지도를 표시하는 방법에 관한 것입니다.
이미지는 아래와 같은 느낌입니다.



사용중인 라이브러리


  • d3-geo
  • i18n-iso-countries
  • react-native-svg
  • topojson-client
  • world-countries

  • 구현 방법



    우선 맵 데이터가 필요합니다.
    일본지도는 조금 뼈가 부러지지만 세계지도는 이 데이터 을 사용하면 쉽게 대응할 수 있습니다.
    
    import worldData from 'src/assets/data/world-110m.json'
    import { feature } from 'topojson-client';
    
    const WorldMapPage: React.FunctionComponent = () => {
      const mapData = feature(worldData, worldData.objects.countries).features;
      ...
    

    화면상에 스포트(빨간색 원)나, 나라를 채우고 싶은 경우는 아래와 같이 실장합니다.

    명소


    import countries from 'world-countries';
    ...
    const WorldMapPage: React.FunctionComponent = () => {
      ...
      const spotGeos = [
        { code: 'JPN', volume: 15 },
        { code: 'USA', volume: 30 },
      ];
      spotGeos.reduce((acc, sg) => {
          const country = countries.find((c) => c.cca3 === sg.code);
          if (!country || !country.latlng) return acc;
    
          acc.push({
            coordinates: country.latlng.slice().reverse(),
            volume: sg.volume,
          });
          return acc;
        }, [] as any);
    

    국가 색상


    import isoCountries from 'i18n-iso-countries';
    ...
    const WorldMapPage: React.FunctionComponent = () => {
      ...
      const paintCountry = [
        { id: 'CHN' },
        { id: 'HKG' },
        { id: 'GBR' },
        { id: 'FRA' },
        { id: 'ITA' },
        { id: 'KOR' },
      ];
      const getColor = (numericId: string) => {
        const alpha3 = isoCountries.numericToAlpha3(numericId);
        return paintCountry.find((c) => c.id === alpha3)
          ? `rgba(38,50,56,0.5)`
          : `rgba(255,255,255,1)`;
      };
    

    메르카토르 다이어그램에 플롯할 수 있도록 매핑 함수를 정의합니다.
    const viewWidth = 800;
    const viewHeight = 450;
    
    const projectMercator = () =>
      geoMercator()
        .scale(viewWidth / ((2 * Math.PI * (360 - 0)) / 360))
        .center([0, 0])
        .translate([viewWidth / 2, viewHeight / 2])
    

    이것으로 준비가 완료됩니다.
    그리고는 react-native-svg 를 사용해, 화면상에 묘사합니다.
    <Svg
      width={size}
      height={size * (viewHeight / viewWidth)}
      viewBox={`0 0 ${viewWidth} ${viewHeight}`}
    >
      <G>
        {mapData.map((d, i) => {
          return (
            <Path
              key={`path-${i}`}
              d={geoPath().projection(projectMercator())(d)}
              fill={`${getColor(d.id)}`}
              stroke="#000000"
              strokeWidth={0.5}
            />
          );
        })}
      </G>
      <G>
        {spots &&
          spots.length > 0 &&
          spots.map((sg, i) => (
            <Circle
              key={`circle-${i}`}
              cx={projectMercator()(sg.coordinates)[0]}
              cy={projectMercator()(sg.coordinates)[1]}
              r={sg.volume}
              fill={`rgba(233,30,99,0.5)`}
            />
          ))}
      </G>
    </Svg>
    
    size 는 여기에서는 화면폭을 취득해 설정하고 있습니다.
    위의 단계에서 국가 채우기와지도에 원을 그릴 수있었습니다.

    일본 지도를 그리려면 일본 지도에 대한 데이터를 가져와야 합니다.
    또한 세계지도와 비교하여 스케일이 다르기 때문에 미세 조정이 필요합니다.
    데이터만 준비할 수 있으면, 묘사는 같은 수법으로 실현 가능하게 됩니다.

    결론



    이번에는, 반년간, 투고가 멀어져 버렸습니다.
    틈새 지식은 정리하고, 언어화하고 조금씩 기사로 할 수 있으면 좋겠습니다.

    좋은 웹페이지 즐겨찾기