React NativeでMapにマーカーを動的に表示させる

<h1>（１）react-native-mapsで動的にマーカーを表示する</h1>

<p>普段はソーシャルワーカー(PSW)として障がいをお持ちの方の支援をしています。ReactやReact Nativeでアプリ作成を楽しんでいます。以前作成したReactNativeアプリでreact-native-mapsを使用したので、まとめておこうと思います。
</p>
<p>参考にした記事<a herf="https://qiita.com/nekoniki/items/7ad0fcf61908a7abecdf">【ReactNative】react-native-mapsで地図の表示領域が描画される度に領域情報を取得する</a><p>React Native のアドベントカレンダーを作成してくれた@nekonikiさんの記事です、ありがとうございます:blush:

<h1>（２）およそ 25000 か所</h1>

<p>こちらは日本全国にある障がい者向けの就労支援事業所の数です、近年とても増えてきておりIT技術を学ぶことができる事業所もあります。すべての事業所を一度マップにしてみたいなと思っていたので、データ集めから始めました。
各都道府県及び政令指定都市が法に基づいて公開しています、しかし各都道府県のデータは様式がさまざま、PDF形式やExcel形式などであり、スクレイピングを併用しながらデータ集めをしました。結構な時間がかかりました💦</p><br>
<p>ちなみに介護保険の全国事業所一覧については、デジタル庁が運営する　<a href="https://www.data.go.jp/">データカタログサイト</a>　で取得することができます、ジオコードも含まれており、すぐにマップに落とすことができるのでとても便利です。</p>

<h1>（３）データの加工</h1>

全国の事業所情報を集めることができたら加工を行っていきます。
まずは、住所からジオコードを作成します。エクセルでyahooジオコードを利用します。
=FILTERXML(WEBSERVICE("https://map.yahooapis.jp/geocode/V1/geoCoder?appid=＜アプリケーションID＞&query=" & ＜住所＞),"//Coordinates")
セルにこの関数を入力することで一気にジオコードが取得できます。うまく変換できていない場合もあるので、それなりにデータチェックが必要です。また、取得されたジオコードを緯度経度にセルを分けます。
csv形式で保存しnodejsを使ってjson形式に変換します。

```js
// tojson.js
const fs = require("fs");
const csv = require("csv");

fs.createReadStream("変換したいファイル.csv").pipe(
  csv.parse({ columns: true }, function (err, data) {
    function writeFile(path, data) {
      const jsonStr = JSON.stringify(data);
      fs.writeFile(path, jsonStr, (err) => {
        if (!err) {
          console.log("Json作成完了");
          console.log(data);
        }
      });
    }
  })
);
// node tojson 変換したいファイル.csv
```
作成したjsonをJavaScript オブジェクトへ変換して準備完了です。

<h1>（４）コード</h1>
<p>さて作成したデータをreact-native-mapsに表示させましょう。
<br>
使用したライブラリ<br>
・react-native<br>
・expo 42.0.1<br>
・react-native-maps 0.28.0
<p>マップのコンポーネントになります</p>
```js
 <MapView
　　onRegionChangeComplete={handleRegionChange} // 地図を移動し終えた後に発火するイベント
　　initialRegion={{　
      latitude: 35.681236, // 初期表示は東京駅に設定
      longitude: 139.767125,
      latitudeDelta: 0.05, // 初期表示範囲
      longitudeDelta: 0.05,
     }}
      minZoomLevel={9} // 初期縮尺レベル
      maxZoomLevel={30}
   >
    // mapを使って作成したデータオブジェクトを展開
    // mapListは作成したデータを必要な形（次のコード）にしてセットする変数
     {mapList.map((item) => { 
        return (
     　  <Marker
           pinColor={"red"}
           key={item.id} // データidをインデックスに　
           title={item.name} 
           coordinate={{
            latitude: Number(item.lat), // 緯度経度を数値型に変換
            longitude: Number(item.lng),
          }}
           >
          <Callout
              onPress={() => {
              navigation.navigate(); // 事業所個別ページに遷移
              }}
            >
          <View>
           <Text>
            {item.name} // ピンをタップしたときに表示させる
           </Text>
          </View>
        </Callout>
       </Marker>
     );
   })}
</MapView>
```
地図にデータを表示させる時に事業所数が多いと読み込みに時間がかかり、またごちゃごちゃするため、一定の範囲内にあるデータのみを表示させましょう。地図を動かす毎に基準のregionが変化し、その範囲内にある事業所が新たに表示されます。

```ts
import { list } from "作成したファイル.js"; // 作成したデータをオブジェクトに変換したjsファイル
import { dummy } from "ダミーファイル.js"; // 初期表示させるダミーデータjsファイル

 const [mapList, setMapList] = useState(dummy); // 初期表示はダミーデータでエラー回避
 const [map, setMap] = useState({}); // onRegionChangeCompleteで取得されるregionをセットする変数

 handleRegionChange = (region) => {
    setMap(region);
        let newList = list.filter(
          (item) =>
            item.lng >= map.longitude - 0.3 && // 緯度経度でフィルターをかけ
            item.lng <= map.longitude + 0.3 && 
            item.lat >= map.latitude - 0.1 &&
            item.lat <= map.latitude + 0.1
        );
        setMapList(newLlist); // 範囲内の事業所をmapListにセット
    }
  };

```
iosはAppleマップを使う場合特に設定は必要ないのですが、androidはapp.jsに下記の記載が必要です。
GCPコンソールから Maps SDK for Android を取得してください。

```ts
"android": {
      "package": "",
      "permissions": [],
      "versionCode": ,
      "config": {
        "googleMaps": {
          "apiKey": ＜APIキー＞ // Maps SDK for Android
        }
      }
    },
```
<h1>（５）終わりに</h1>
<p>実際の動きです</p>
![20211212_012934 (1) (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635004/a98c821c-28da-8827-1596-fa25d0f36c95.gif)

<p>二日続けてAdvent Calendarに参加させてもらいました:thumbsup:書き留めていたものを年末に書き出して来年も良いreactな一年にしたいなと思っています！</p>