6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

React Native で世界地図を表示する

Last updated at Posted at 2019-12-16

はじめに

仕事で React Native を使って開発をしており、知見が溜まってきたのですが、記事に起こそうと悩んでる間にかなり経ってしましました。

今回は、画面上に世界地図を表示する方法についてです。
イメージは下記の感じです。

Simulator Screen Shot - iPhone 11 Pro Max - 2019-12-16 at 22.37.43.png

使用しているライブラリ

  • 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 はここでは画面幅を取得して設定しています。
上記の手順で、国の塗りつぶしと、地図上に円をプロットすることができました。

日本地図を描きたい場合は、日本地図用のデータを取得する必要があります。
また、世界地図と比べて縮尺が異なるので微調整が必要です。
データさえ用意できれば、描写は同様の手法で実現可能となります。

おわりに

今回は、半年間、投稿が遠のいてしまいました。
ニッチな知見は整理して、言語化して少しずつ記事にできればと思います。

6
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?