はじめに
仕事で 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
はここでは画面幅を取得して設定しています。
上記の手順で、国の塗りつぶしと、地図上に円をプロットすることができました。
日本地図を描きたい場合は、日本地図用のデータを取得する必要があります。
また、世界地図と比べて縮尺が異なるので微調整が必要です。
データさえ用意できれば、描写は同様の手法で実現可能となります。
おわりに
今回は、半年間、投稿が遠のいてしまいました。
ニッチな知見は整理して、言語化して少しずつ記事にできればと思います。