JavaScriptですぐに使える、市区町村のポリゴンデータを公開した話

# サマリ🗾
日本の全ての市区町村の境界線データを、`JavaScript`からすぐに使うことができるデータセット`jpCityPolygon `を公開しました。
面倒な緯度経度の計算だとか、メルカトルが云々とか考えずに、ただそこに市区町村ポリゴンを描きたいあなたにお勧めです。
![logo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542654/e08e9cea-7b53-0e94-1732-ab19a82c20bd.png)

# 成果物
[jpCityPolygon: a dataset consisting of polygon data of all cities in Japan.](https://github.com/tetunori/jpCityPolygon)
~~2021/10/21 現在のversionは`0.8.0`のbeta releaseです。~~
~~2021/10/23 現在のversionは`0.9.0`のbeta releaseです。~~
2021/10/26 現在のversionは`1.0.0`です。

これを使うと、この様なGenerative Artも秒で描けます。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">jpCityPolygonのサンプルとして、思い入れのある街をジェネレーティブアートにできるツール <a href="https://twitter.com/hashtag/GenerativeHometown?src=hash&amp;ref_src=twsrc%5Etfw">#GenerativeHometown</a> を作りました。<br>スマホでもPCでも、ドロップダウンで街を選ぶだけで、アートができあがるので、生まれ故郷や住んでる町で楽しんでみてください！<a href="https://t.co/loq00lmP1B">https://t.co/loq00lmP1B</a> <a href="https://t.co/C2uVCkMQOA">pic.twitter.com/C2uVCkMQOA</a></p>&mdash; Tetsunori NAKAYAMA | 中山 哲法 (@tetunori_lego) <a href="https://twitter.com/tetunori_lego/status/1451481707463405574?ref_src=twsrc%5Etfw">October 22, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
 - [Generative Hometown](https://tetunori.github.io/jpCityPolygon/sample/generativeHometown/)

# きっかけ
`Saitama.js`という名前のイベントでanozonさんが発表されていた、[『埼玉県の描き方』](https://t.co/1Z7KcDtmj7?amp=1)の内容が面白かったので、自分でも、**思い入れのある土地、なんなら都道府県よりも、もっと愛着のある市区町村レベルで絵を描けないかな？**と調べ始めました。
実際に使えそうなデータがないかと調べ始めると、ライセンス的に使用が難しいものだったり、データが不正確だったり・・・そして、なによりJSでパッとURLにアクセスしたらすぐ描けるようなデータというものは見当たりませんでした。(検索力ないだけかも・・・)

それなら自分で作ろうと思い立ったのが、本取り組みのきっかけです。

# 簡単な使い方
## 環境
今回のデータはWebから扱えるように`JavaScirpt`の`Object`データとして公開しています。

## データのインポート
`https://tetunori.github.io/jpCityPolygon/dist/v1.0.0/`の下にすべての市区町村に対応したスクリプトファイルがあるので、お好きな都市を選んでください。
ファイルは`<都道府県名>/<市区町村名>.min.js`および`<都道府県名>/<市区町村名>.js`の両方の形式で提供しています。もちろん`min.js`のほうがファイルサイズが小さいので、使用される際はこちらがお勧めです。なお、`v0.9.0`より、都道府県全域のポリゴンデータも追加しました。ファイルは`<都道府県名>/<都道府県名>.min.js`および`<都道府県名>/<都道府県名>.js`の両方の形式で提供しています。
[GitHubのリポジトリ](https://github.com/tetunori/jpCityPolygon/tree/main/dist/v1.0.0)へアクセスし確認してみてください。

例えば、**北海道北広島市**というデータを取得する場合は、このような`script`タグを読み込んでください。

```html 
<script src="https://tetunori.github.io/jpCityPolygon/dist/v1.0.0/北海道/北広島市.min.js"></script>
```

```html 
<script src="https://tetunori.github.io/jpCityPolygon/dist/v1.0.0/北海道/北海道.min.js"></script>
```

## データを使う
### オブジェクトの構成
全ての`<都道府県名>/<市区町村名>.js`と`同.min.js`は１つのメインオブジェクト`<都道府県名><市区町村名>`を持っています。また、全ての`<都道府県名>/<都道府県名>.js`と`同.min.js`は１つのメインオブジェクト`<都道府県名>`を持っています。

先程の例ですと、`北海道北広島市`オブジェクトや`北海道`オブジェクトが含まれています。 
このオブジェクトには、下記の５つのプロパティが含まれています： 

- `prefecture`: `String`
 - 都道府県名
- `name`: `String`
 - 市区町村名
- `latlons`: ポリゴンデータの`Array`
 - 緯度経度情報の**生値**。`{'lat':..., 'lon':...}`の形式で複数のポリゴンを形成。
- `polygons`: ポリゴンデータの`Array`
 - 緯度経度情報からメルカトル投影で平面にマッピングした`(x, y)`情報の**生値**。`{'x':..., 'y':...}`の形式で複数のポリゴンを形成。
- `normalizedPolygons`: ポリゴンデータの`Array`
 - 上記`polygons`のデータをサイズ360*360にちょうど収まるように正規化したポリゴンデータ。`{'x':..., 'y':...}`の形式で複数のポリゴンを形成。
 - **特にこのデータを使うことをお勧めします！**

### 実際に`p5.js`で使ってみる
なんてシンプルなんだ！

``` javascript
function setup() {
  createCanvas(360, 360);
}

function draw() {
  background(220);

  // 今回はnormalizedPolygonsを使います。
  const polygons = 北海道北広島市.normalizedPolygons;
  // const polygons = 北海道.normalizedPolygons;

  // メインのオブジェクトは複数のポリゴンデータで構成されています。
  polygons.forEach((polygon) => {
    beginShape();
    for (let i = 0; i < polygon.length; i++) {
      // vertexに放り込むだけ！
      vertex(polygon[i].x, polygon[i].y);
    }
    endShape();
  });
}
```

## 実装サンプル
### Basic Sample: シンプルに境界線を描く
<img src="https://tetunori.github.io/jpCityPolygon/images/basic1.png" alt="basic1" width="360px">  
 - [Sample On GitHub](https://tetunori.github.io/jpCityPolygon/sample/basic/)
 - [Sample On OpenProcessing](https://openprocessing.org/sketch/1316557)

### Generative Hometown: ジェネラティブアートにする
<img src="https://tetunori.github.io/jpCityPolygon/images/generativeHometown1.png" alt="generativeHometown1" width="360px">  
 - [Sample On GitHub](https://tetunori.github.io/jpCityPolygon/sample/generativeHometown/)
 - [Sample On OpenProcessing](https://openprocessing.org/sketch/1316562)

# 技術的なポイント
## 元データの素性
正確性とライセンスの都合から、国土交通省のデータを使いました。比較的緩い制約で使えるので大変助かります。
[「国土数値情報（行政区域データ）」（国土交通省）](https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-v2_3.html)
※ なお、データの基準年月日は平成31（2019）年 1月 1日時点となります。

## メルカトル投影のロジック
いろいろ調べたりしたのですが、緯度経度が与えられたときに、XY平面に変換するロジックは下記で実装してみました。たぶんあっていると思うけどあまり自信がないです。

``` javascript 
// (中略) 
// k: each (lat, lon) coordinates
// calucurate as Mercator projection
const radians = (deg) => deg * (Math.PI / 180);
const polygon = l.map((k) => ({
  x: radians(k[0]),
  y: Math.log(Math.tan(Math.PI / 4 + radians(k[1]) / 2)),
}));
```

## サンプルの実装
### スクリプトの動的ロード
ポリゴンデータを含んでいるため結構なサイズのファイルになってしまい、事前に全部読み込むことは現実的ではありません。そこでサンプルでは、市区町村が選択された際に動的にスクリプトを読みこむようにしてみました。ロードのパフォーマンスも個人的には満足しています。

### generativeHometownのパターン生成について
SYM380さんが作られているスーパークールなツール、[p5.pattern](https://github.com/SYM380/p5.pattern)を使っています。下記のサンプルのようにめちゃめちゃ簡単にパターン生成できるので、大変たすかりました！みんな積極的に使おうな。
[How to use p5.pattern](https://openprocessing.org/sketch/1278485) by SYM380